|
for example(My IDE is vs 2008):
#include <iostream>
#include <iterator>
#include "reflection.hpp"
using namespace agm::reflection;
using namespace std;
class Widget
{
CLASS(Widget, NullClass);
METHOD(public, void, print, (const string &msg) )
{
cout << "s2:" << &msg << endl;
cout << "message: " << msg << endl;
}
CONSTRUCTOR(public, Widget, ())
{
cout << "Widget:: default constructor called" << endl;
}
public:
virtual ~Widget() {}
};
int main()
{
string str("hello world!");
cout << "s1:" << &str << endl;
Widget w;
Widget::getClass().getMethod("print").invokeVoid(&w, str);
return 0;
}
|
|
|
|
|
I'm just wondering if anyone has tried to use this library from multiple DLL's? And if so, how they handled the fact that there is a separate reflection database for each execution unit? (One for the main executable, and another for each loaded DLL that uses this library).
Further, is there any new updates to this library? I've seen in the document that events are something that the author wanted to implement, but as of yet, I'm still waiting for an implementation.
Is there an official project page for this library on SourceForge or Google Code?
modified on Tuesday, November 24, 2009 8:04 AM
|
|
|
|
|
Good question, I also want to know if the AGM:LibReflection support cross DLL situation.
In the Base dll, I implement some class, and in other dll's I want to extend the derived class, and need to manager they implementation in the Base dll.
Reflection is good, but I don't know whether it is support.
Best Regards
|
|
|
|
|
One really cool feature that I would really love to see in LibReflection is attributes (or annotations) that can be applied on reflective Properties, Fields, or Methods.
For example:
PROPERTY( int, Length );
ATTRIBUTE( Length, "EditReadOnly", true );
ATTRIBUTE( Length, "DefaultValue", 0 );
ATTRIBUTE( Length, "Description", "The length of the string" );
Where the attribute takes several parameters:
- Name of the property, field, or method to apply the attribute to,
- The name of the attribute as a string,
- The value of the attribute (either as a string, or the actual type depending on the attribute)
This way, we can use these values as hints as to how the properties, or fields should be used in an editor for example. Other attributes can be applied to methods to describe things like how a method should be executed. For example, an attribute called "Client" specifies that a method should be executed only on the client process, while an attribute of "Server" describes a method that should only be executed on the server process. This would be very useful for game engine programming for example.
|
|
|
|
|
I just want to point out, if anyone has tried to use the Class::forName( const std::string& name ) static method to get a class by name, in the docs and examples, it uses:
const Class* widgetClass = Class::forName("Widget");
This won't work exactly as is because you must append "class" to the class name:
const Class* widgetClass = Class::forName( "class Widget" );
Took me a while to figure that one out!
Anyways, great little library. I got it to compile (VS2008) in just a short time and I updated my framework and now I can dynamically create types by name.
|
|
|
|
|
I was just thinking... Do you think this is compiler specific? I don't know exactly how the full name is created, but perhaps the (preprocessor compiler? template compiler?) is appending "class" to type names? Or is it the RTTI that is doing this? Maybe this doesn't happen on other compilers?
Anybody have any ideas about that?
|
|
|
|
|
Okay, I answerd my own question. The "class Widget" comes from the name of the type_id object returned by the RTTI typeinfo() method.
The "class" prefix, is this platform specific? Is RTTI platform dependant? Will LibReflection work if I disable RTTI?
|
|
|
|
|
RTTI is actually compiler specific. It can be platform specific too. But my experience told me that even within the same platform, compiling the same code will yield different class name from the typeinfo() method. That's why there is a big section within the .cpp file that handle the class name mangle. It is not hard to figure out how to fix it but you just really need to know what your compiler going to return as the class name.
|
|
|
|
|
I know .constructor() with no arguments registers default contructor.
But how can I register non-default constructors ?
|
|
|
|
|
Because there is no way we can get a method pointer to a constructor, we will use a "Type Wrapper" to denote the type you are specifying. As usual, you can specify up to 20 parameters. For example, the class
class Widget {<br />
public:<br />
Widget() {};<br />
Widget(int x, int y):m_x(x), m_y(y) {}<br />
Widget(int x, int y, int width, int height): m_x(x), m_y(y), m_width(width), m_height(height) {}<br />
Widget(const Widget& that): m_x(that.m_x), m_y(that.m_y), m_width(that.m_width), m_height(that.m_height)<br />
, m_visible(that.m_visible), m_enabled(that.m_enabled) {}<br />
virtual ~Widget(){};<br />
the constructor should be defined as:
<br />
const ReflectiveClass<Widget> clsdef = ReflectiveClass<Widget>()<br />
.constructor()<br />
.constructor(Type2Type<int>(), Type2Type<int>())<br />
.constructor(Type2Type<int>(), Type2Type<int>(), Type2Type<int>(), Type2Type<int>())<br />
.constructor(Type2Type<const Widget&>())<br />
;<br />
|
|
|
|
|
Hi,
I'm trying to compile this library int Windows CE, almost everything works, except constructors stuff.
I know that problem is in ARM compiler from EVC because the library compiles fine in Visual Studio.
the part that doesn't work is the following:
template <class c="">
static C *__new_instance_ptr__(void* ptr)
{
return new (ptr) T();
}
template <class c="">
static C *(* __create_new_instance_ptr__(C *(*)()))(void *)
{
return & __new_instance_ptr__<c>; <-- ERROR C2275
}
The error is:
error C2275: 'C' : illegal use of this type as an expression
So, i am looking for some workaround for this
thanks in advance
|
|
|
|
|
I have just downloaded unzipped and loaded the project in VS 2005. I hit the build button and.... (see below).... Any suggestions
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char=""> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char=""> > &,class agm::reflection::Class const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABVClass@reflection@agm@@@Z) referenced in function "void __cdecl print_class(class agm::reflection::Class const &)" (?print_class@@YAXABVClass@reflection@agm@@@Z)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall agm::reflection::Class::Class(char const *,class agm::reflection::Class const *,unsigned int,void * (__cdecl*)(void),void * (__cdecl*)(void *),void const * (__cdecl*)(void const *),class type_info const &,class type_info const &,class type_info const &,class type_info const &,class type_info const &,class type_info const &,class type_info const &,class type_info const &)" (??0Class@reflection@agm@@QAE@PBDPBV012@IP6APAXXZP6APAXPAX@ZP6APBXPBX@ZABVtype_info@@7777777@Z) referenced in function "protected: static class agm::reflection::Class const * __cdecl Foo::getClassStaticPtr(void)" (?getClassStaticPtr@Foo@@KAPBVClass@reflection@agm@@XZ)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall agm::reflection::__register_method__::__register_method__(struct agm::reflection::__callable__ *,class agm::reflection::Class const *,enum agm::reflection::ACCESS_TYPE,char const *,char const *,char const *,char const *)" (??0__register_method__@reflection@agm@@QAE@PAU__callable__@12@PBVClass@12@W4ACCESS_TYPE@12@PBD333@Z) referenced in function "public: __thiscall Foo::__method_action__36::__method_action__36(void)" (??0__method_action__36@Foo@@QAE@XZ)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall agm::reflection::__register_static_method__::__register_static_method__(struct agm::reflection::__callable__ *,class agm::reflection::Class const *,enum agm::reflection::ACCESS_TYPE,char const *,char const *,char const *)" (??0__register_static_method__@reflection@agm@@QAE@PAU__callable__@12@PBVClass@12@W4ACCESS_TYPE@12@PBD33@Z) referenced in function "public: __thiscall Foo::__static_method_get_code__44::__static_method_get_code__44(void)" (??0__static_method_get_code__44@Foo@@QAE@XZ)
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall agm::reflection::__register_property__::__register_property__(struct agm::reflection::__property_base__ *,class agm::reflection::Class const *,char const *,char const *,class type_info const &)" (??0__register_property__@reflection@agm@@QAE@PAU__property_base__@12@PBVClass@12@PBD2ABVtype_info@@@Z) referenced in function "public: __thiscall Foo::__property__length<int>::__property__length<int>(void)" (??0?$__property__length@H@Foo@@QAE@XZ)
1>main.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall agm::reflection::Class::~Class(void)" (??1Class@reflection@agm@@UAE@XZ) referenced in function "void __cdecl `protected: static class agm::reflection::Class const * __cdecl Foo::getClassStaticPtr(void)'::`2'::`dynamic atexit destructor for '_class''(void)" (??__F_class@?1??getClassStaticPtr@Foo@@KAPBVClass@reflection@agm@@XZ@YAXXZ)
1>.\Debug/agm_reflection.exe : fatal error LNK1120: 6 unresolved externals
|
|
|
|
|
The problem is, the project does not include all the source files needed to build the project properly.
If you download the LibReflection_2.zip file (in this article), it contains a project file that has a small test (main.cpp). You also need to include the "include/bk/reflection.cpp" source file in the project before all the functions will be linked in (I thought this was a header only library?).
You might still get a link error because the main.cpp includes the wrong header file (by default, it will use the old header). You have to change the header included in the main.cpp file from "reflection.hpp" to "bk/reflection.hpp" . This is because the project is configured to include the "include" folder in the include search path, and it will find the old header first.
If you are a purist like me, and you don't like seeing all the warnings, you might want to disable the warnings for the exception specification (warning C4290). Edit the "include/bk/reflection.hpp" file, just after the include guard change the following lines from:
#ifdef MSVC
#pragma warning (disable: 4786)
#pragma warning (disable: 4003)
#endif
to
#ifdef _MSC_VER
#pragma warning (disable: 4786)
#pragma warning (disable: 4003)
#pragma warning (disable: 4290)
#endif
I've been able to compile and run the sample program in VS2008 after performing these steps.
|
|
|
|
|
Hi,
I tryed to build the project without any change.
It gives me these errors ( at lines 29, 31, 37, 42, 47 and 510) for the file main.cpp :
------ Build started: Project: agm_reflection, Configuration: Debug Win32 ------<br />
<br />
Compiling...<br />
main.cpp<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(30) : error C2039: 'Foo' : is not a member of 'Foo::__method_action__29'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(30) : see declaration of 'Foo::__method_action__29'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(34) : error C2039: 'Foo' : is not a member of 'Foo::__method_action1__33'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(34) : see declaration of 'Foo::__method_action1__33'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(38) : error C2039: 'Foo' : is not a member of 'Foo::__static_method_get_code__37'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(38) : see declaration of 'Foo::__static_method_get_code__37'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(43) : error C2039: 'Foo' : is not a member of 'Foo::__static_method_get_code1__42'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(43) : see declaration of 'Foo::__static_method_get_code1__42'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(48) : error C2039: 'Foo' : is not a member of 'Foo::__static_method_print_code__47'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(48) : see declaration of 'Foo::__static_method_print_code__47'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(52) : error C2039: 'Foo' : is not a member of 'Foo::__static_method_print_code1__51'<br />
c:\Projets\libreflection2_src\LibReflection\main.cpp(52) : see declaration of 'Foo::__static_method_print_code1__51'<br />
<br />
Build log was saved at "file://c:\Projets\libreflection2_src\LibReflection\Debug\BuildLog.htm"<br />
agm_reflection - 6 error(s), 0 warning(s)<br />
<br />
<br />
---------------------- Done ----------------------<br />
<br />
Build: 0 succeeded, 1 failed, 0 skipped<br />
<br />
<br />
It seems that the defined typedef 'ClassType' is unknow.
Update : It works under the beta version of VS .NET 2005. But because it is a beta version, i have to build it under VS.NET 2003. If someone can help me please ...
-- modified at 5:11 Thursday 6th October, 2005
|
|
|
|
|
I have this problem too.
Any body can give us some suggestions?
|
|
|
|
|
The source zip file has been updated. This is an attempt to fix compilation issue with VC++.
|
|
|
|
|
In the coming weeks, I will be updating the source once again. This time, I will add dynamic declaration of reflective class. That is, the ability to add class definition outside the class itself.
An example will look something like the following:
static const ReflectiveClass<Widget> widget_cls = ReflectiveClass<Widget>()<br />
.constructor0()<br />
.property(&Widget::get_x, &Widget::set_x, "x")<br />
.property(&Widget::get_y, &Widget::set_y, "y")<br />
.property(&Widget::get_width, &Widget::set_width, "width")<br />
.property(&Widget::get_height, &Widget::set_height, "height")<br />
.property(&Widget::get_visible, &Widget::set_visible, "visible")<br />
.property(&Widget::get_enabled, &Widget::set_enabled, "enabled")<br />
.static_field(&Widget::version, "version")<br />
.method(&Widget::add, "add")<br />
.static_method(&Widget::get_version_string, "get_version_string")<br />
.field(&Widget::m_x, "m_x")<br />
.field(&Widget::m_y, "m_y")<br />
.field(&Widget::m_width, "m_width")<br />
.field(&Widget::m_height, "m_height")<br />
.field(&Widget::m_visible, "m_visible")<br />
.field(&Widget::m_enabled, "m_enabled");<br />
<br />
const Class * cls = widget_cls.get();<br />
<br />
<br />
And Widget class will NOT need to use any MACRO to define the reflective properties. Let me know if this will be useful.
|
|
|
|
|
Then it'll look more and more like boost::python or luabind. Which is a good thing, imho
Will ReflectiveClass be dynamic, i.e. can we add fields, properties, methods etc at runtime at will?
-sk
|
|
|
|
|
oh yeah, it does look more and more like boost::python, isn't it?!.
Yes, you can dynamically add declared method into ReflectiveClass provided you can obtain the original non-const version of the ReflectiveClass instance. But since declaring a class method in ReflectiveClass requires that you pass in a member-function, it will be difficult to define it during runtime. Unless you know a way to turn a regular C++ function into method function. But a static method, on the order hand is simply a regular C++ function which means you can add as many as you wanted.
|
|
|
|
|
Okay, now that I have been using the LibReflection in writing my own expression evaluator, I can see cases where the ability to dynamically add any function to the class might be useful. I changed the implementation such that when using ReflectionClass<>::method() , user can now add static function as class method function. The requirement is that the static function must accept the object pointer as the first parameter (similiar to the way mem_fun turning a member function to a functor).
|
|
|
|
|
Hi,
Great job!
Could you please provide a makefile for gcc ?
I seem to have problems compiling the main.cpp...
Thanks!
|
|
|
|
|
I basically just do:
gcc -Iinclude -Wall main.cpp -o main
What compile error do you see? I tried to update the src zipfile to fix problem with MS VC compiler but I can't seem to be able to do it...
|
|
|
|
|
Hi,
Thanks for the quick reply.
When I run
gcc -Iinclude -Wall main.cpp -o main 2>&1 | more
I get
include/reflection.hpp: In function `static bool
agm::reflection::MethodBase::testCompatible0(agm::reflection::__callable__*,
const std::type_info&, const std::type_info&, const std::type_info&, void*)
[with int param_size = 0]':
include/reflection.hpp:2015: instantiated from here
include/reflection.hpp:1816: warning: unused variable `
__gnu_cxx::__normal_iterator<const std::type_info*="" const*,="" std::vector<const
="" std::type_info*,="" std::allocator<const=""> > > i'
include/reflection.hpp: In function `static std::string
agm::reflection::MethodBase::findMismatchedType0(agm::reflection::__callable__*,
const std::type_info&, const std::type_info&, const std::type_info&) [with
int param_size = 0]':
include/reflection.hpp:2015: instantiated from here
include/reflection.hpp:1794: warning: unused variable `
__gnu_cxx::__normal_iterator<const std::type_info*="" const*,="" std::vector<const
="" std::type_info*,="" std::allocator<const=""> > > i'
/tmp/cc5WkO8o.o(.text+0xb): In function `print_class(agm::reflection::Class const&)':
: undefined reference to `std::basic_ostream<char, std::char_traits<char=""> >& std::endl<char, std::char_traits<char=""> >(std:
:basic_ostream<char, std::char_traits<char=""> >&)'
/tmp/cc5WkO8o.o(.text+0x2a): In function `print_class(agm::reflection::Class const&)':
: undefined reference to `std::cout'
/tmp/cc5WkO8o.o(.text+0x2f): In function `print_class(agm::reflection::Class const&)':
and so on...
|
|
|
|
|
I compiled the main.cpp after some changes on the original hpp.
Here is the compilation report on the ORIGINAL hpp:
[devnirl@dragon LibReflection]$ gcc -Iinclude -Wall main.cpp -o main 2>&1 | more
include/reflection.hpp: In function `static bool
agm::reflection::MethodBase::testCompatible0(agm::reflection::__callable__*,
const std::type_info&, const std::type_info&, const std::type_info&, void*)
[with int param_size = 0]':
include/reflection.hpp:2013: instantiated from here
include/reflection.hpp:1814: warning: unused variable `
__gnu_cxx::__normal_iterator<const std::type_info*="" const*,="" std::vector<const
="" std::type_info*,="" std::allocator<const=""> > > i'
include/reflection.hpp: In function `static std::string
agm::reflection::MethodBase::findMismatchedType0(agm::reflection::__callable__*,
const std::type_info&, const std::type_info&, const std::type_info&) [with
int param_size = 0]':
include/reflection.hpp:2013: instantiated from here
include/reflection.hpp:1792: warning: unused variable `
__gnu_cxx::__normal_iterator<const std::type_info*="" const*,="" std::vector<const
="" std::type_info*,="" std::allocator<const=""> > > i'
/tmp/cc5qbYVF.o(.text+0xb): In function `print_class(agm::reflection::Class const&)':
: undefined reference to `std::basic_ostream<char, std::char_traits<char=""> >& std::endl<char, std::char_traits<char=""> >(std:
:basic_ostream<char, std::char_traits<char=""> >&)'
/tmp/cc5qbYVF.o(.text+0x2a): In function `print_class(agm::reflection::Class const&)':
: undefined reference to `std::cout'
/tmp/cc5qbYVF.o(.text+0x2f): In function `print_class(agm::reflection::Class const&)':
|
|
|
|
|
Anonymous wrote:
include/reflection.hpp:1814: warning: unused variable `
__gnu_cxx::__normal_iterator std::type_info*, std::allocator > > i'
This is because there is no argument when param_size = 0. This is an easy fix by referencing i.
i=i;
Anonymous wrote:
: undefined reference to `std::basic_ostream >& std::endl >(std:
:basic_ostream >&)'
/tmp/cc5qbYVF.o(.text+0x2a): In function `print_class(agm::reflection::Class const&)':
: undefined reference to `std::cout'
This look like that the libstdc++.a was not linked again.
gcc -Iinclude -Wall -lstdc++ main.cpp -o main
|
|
|
|
|