|
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
|
|
|
|
|
Do you realy write code like this:
"METHOD(public, void, store2nd, (Y y)) "
I wonder how if you ever use IntelliSense and how does it work for you...
Anyway, nice implementation for using "reflection" in C++.
|
|
|
|
|
yes, that syntax does suck. I wonder what the chances are of being able to make a pre-compiler to convert normal function defs into refelection registration macros... I've never atempted such a thing.
|
|
|
|
|
Actually, such attempt had already being made. In general, there are 2 ways that I found doing reflection in C++. The first approach is the "ugly" macro syntax you're referring to. Example are the AGM::LibRefelection and Visual Component Framework (VCF)[^].The second approach is by reading and prasing the header to obtain the class definition. An example of it is SEAL C++ Reflection[^] library. The reason I went with the AGM::LibReflection macro implementation is for serveral reason.
(1) Most of the other framework that has reflection included are defined mostly for visual component. You will need to adapt and accept their framework -- including Event dispatching... As for me, I am writing backend server service that does not need them.
(2) The AGM::LibReflection does not require a particular base class that your object must inherit.
(3) I liked the SEAL C++ Reflection, but the library has heavy dependencies on many external library. Althought I have not tried, it might be able to extract just the reflection portion from that SEAL library. The distribution of SEAL wasn't really setup for do-it-yourself compliation.
(4) The number of the object that I need to explore reflection is relatively small. I only care about those class that I need to re-configure at runtime externally.
(5) We do not want to link again ton of external packages. It makes this package relatively "light" and small...
For heavy use of C++ reflection, you probably want to look at package like SEAL C++ to see if you can accept them. You are right that the syntax isn't really user friendly...
|
|
|
|
|
I think I may have found a way to avoid the limitation of having to first create an instance.. I'd be curious to hear what you think.
It creates a little singleton, registers the class with a small instantiator function and then the singleton deletes itself ( which I think is ok given the circumstance ).
Its not quite done, I think I can also add a number of base classes using a seperate ADDBASECLASS macro. I'll probably have to make a BEGINCLASSDEF and ENDCLASSDEF so I dont have to make more singletons.
//=========================================
//.h
//=========================================
#pragma once
typedef void* NewInstanceFunc( void );
class TypeRegistration
{
public:
TypeRegistration(void);
~TypeRegistration(void);
void RegisterType( char* name, NewInstanceFunc* pFunc );
};
extern TypeRegistration g_TypeRegistration;
#define REGISTERCLASSTYPE(CLASS_NAME)\
void* _create_new_instance_##CLASS_NAME( void ) { return new CLASS_NAME(); } \
class _register_class_type_##CLASS_NAME\
{\
public:\
_register_class_type_##CLASS_NAME()\
{\
g_TypeRegistration.RegisterType( ("CLASS_NAME"), &_create_new_instance_##CLASS_NAME );\
delete this;\
};\
};\
_register_class_type_##CLASS_NAME* g_register_class_type_##CLASS_NAME = new _register_class_type_##CLASS_NAME();
//=========================================
//.cpp
//=========================================
#include "StdAfx.h"
#include "typeregistration.h"
//===============--------------------------
// Globals
TypeRegistration g_TypeRegistration;
TypeRegistration::TypeRegistration(void)
{
}
TypeRegistration::~TypeRegistration(void)
{
}
void
TypeRegistration::RegisterType( char* name, NewInstanceFunc* pFunc )
{
//save function pointer an what ever other data here
void* p = (*pFunc)();
}
//=========================================
//usage
//=========================================
in the .cpp of the target class add these lines
#include "TypeRegistration.h"
REGISTERCLASSTYPE(ClassName);
|
|
|
|
|
Livid, you created quite a bit of code that may indeed serve your purpose. But, however, you can simply define REGISTERCLASSTYPE macro as
#define REGISTERCLASSTYPE(ClassName) static void * __XXX_##ClassName = delete ( new ClassName() );
I thought of somethings similiar; but I actually do not like this solution for serveral reasons
(1) It makes assumption that there is a default constructor, it is available and that the constructor is public and callable. And the class is not an abstract base class.
(2) Same assumption about the destructor
(3) The extra code will make template class invalid. Yes, there is a way to solve it; but your current implementation is not yet there.
(4) It requires the developer to put an extra declaration outside the class definition. If this would have been a requirement that the developer can live with, the developer can simply just define a static instance:
const ClassName my_class_instance;
and that serve the same purpose as well...
Regarding defining multiple base class using ADDBASECLASS macro... Yes, you can indeed capture the information, but its usage is limited in term of what the reflection library can do. One of the reason that why we insist the requirement of single non-virtual inhertiance is that we want to make sure that for any Derived *p , the following is true: p == static_cast<Base *> (p) . It makes casting to and from Base class simple. Yes, we can still retrofit our reflection library to work in a limited way. For example, if a Method is defined in the base class and you intended to invoke it, the reflection library need to adjust the Derived * . The situation becomes a little complex when you are invoking a virtual function that may or may not being overriden in the Derived class. The usage is limited in the way that automatic casting (whether implicit or down casting) will not work for parameter type. This limitation is due to we have no way of knowing if a particular parameter is a pointer or reference type ahead of time and therefore, it is impossible to implement the templated invoke() methods. Beside, you can re-assign a referrence type parameter anyway. The question is really how often the multiple base classes is really needed. And can you live with the fact that the second base class will have limited behavior compare to first base class. In any case, yes, we can certainly captures that multiple base classes... but is it worth it?
Regarding your proposed MACRO BEGINCLASSDEF and ENDCLASSDEF , yes it will help to group all of the definition together, but it also restrict the programmer from providing an inline defintion of the method inside the class declaration. I am just guessing at this point because I have not seen how you plan to implement that. You have a good point about the need to group all of the reflective constructor/method/field together. This is due to the way that the LibReflective library insert nested empty class element within the class declaration. Because the compiler are require to allocate at least 1 bytes for any structure (even if there is no data member), the class size can become fairly large if you mix reflective declaration and field. I should probably state this as a guideline in the article.
|
|
|
|
|
Thanks for your feedback, I am curious how you handle templated classes. I think I will be typedefing anything I use for refelections, bit if there is a better way...
The assumption about a default pramaterless constructor seemed fine to me, as that is a restriction of c# also ( you dont NEED a paramterless contructor but it quite a bit more complicated to not have them ). As for the single inheriting, that is also a restriction of c#, one I really don't like. I figured it wouldn't be that hard to implement multiple inheriting, tho I havent got far enough in to hit any walls. Do you have anything similar to interfaces in c#? It similar to multiple inheritance but you can derive from multiple pure virutal classes.
All I really want to use reflection for is a fancy factory, so I wont be needing the methods, and my property system will be available after a class has been created.
Jason
|
|
|
|
|
As you already know, the real class registration (the point of time the class is known to the system) is when the object of that class instaniated. And when an object instantiate, the exact type of all of its templated parameter are known, so that is no mistake as to what type of object it is. The other reason when it works is that a templated class with different template parameter are completely 2 seperate class that does not share any global space. Each class has its own set of static data variables -- and static data variable are used extensively as the method of registering the class into LibReflection.
I have absolutely zero knowledge about c#, so this LibReflection library will probably fail to compile in C#. I am even amaze if it actually compile under VC++ due to the heavy MACRO that it rely on. Can someone actually try to compile it on VC++ ? Which version work and which doesn't ??
|
|
|
|
|
I tried to compile both in Vc 6.0 and in Vc .NET.
Both of them failed but the warnings and errors were few (something like 4 or 5).
I tried to check how the errors could be checked but i realized it was too complex for a person who didn't write the code.
|
|
|
|
|
pinturic wrote:
I tried to compile both in Vc 6.0 and in Vc .NET.
Both of them failed but the warnings and errors were few (something like 4 or 5).
Can you send me the error message? Perhaps I can take a look...
|
|
|
|
|
One line the MSVC isn't able to understand now is this:
std::string errmsg = findMismatchedType0< 0 > (m_callable, typeid(void), typeid(void), typeid(void));
And this is the error signaled:
reflection.hpp(2016) : error C2677: binary '>' : no global operator defined which takes type 'const class type_info' (or there is no acceptable conversion)
Moreover i wonder why the compiler doesn't complain about the other line below:
std::string errmsg = findMismatchedType##N< N __REPEAT(N, __TYPE_ARG__, __COMMA__, __COMMA__) > (m_callable, typeid(void), typeid(void), typeid(void));
|
|
|
|
|