|
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));
|
|
|
|
|
That's strange.
Why would the compiler think it is doing a '>' operator? Perhaps it doesn't like a non-typed templated argument <0> ? And the other marco will expand to findMismatchedType1<1, T> which will have a type argument.
But if that is the case, why the line
if (testCompatible0< 0 > (m_callable, typeid(void), typeid(void), typeid(void), 0))
would not complain...
what happen if you change the line from
std::string errmsg = findMismatchedType0< 0 > ....
to
std::string errmsg = "";
??
|
|
|
|
|
With this changement:
std::string errmsg = "";
it worked !!
|
|
|
|
|
I actually found it more surprising that it works... because I found no reason that the (if) line above this offending line actually didn't generate similiar error:
if (testCompatible0< 0 > (m_callable, typeid(void), typeid(void), typeid(void), 0))
looks like this is a subtle compiler bug...
what if you change the offending line to:
std::string errmsg ( findMismatchedType0< 0 > (m_callable, typeid(void), typeid(void), typeid(void)));
or
std::string errmsg ( MethodBase::findMismatchedType0< 0 > (m_callable, typeid(void), typeid(void), typeid(void)));
If these don't work, then we need to single out the findMismatchedType0 to an non-template implementation...
|
|
|
|
|
Both of them generate this kind of error:
error C2783: 'class std::basic_string<char,struct std::char_traits<char="">,class std::allocator<char> > __cdecl agm::reflection::MethodBase::findMismatchedType0(s
truct agm::reflection::__callable__ *,const class type_info &,const class type_info &,const class type_info &)' : could not deduce template argument for 'param_size'
|
|
|
|
|
pinturic wrote:
error C2783: 'class std::basic_string,class std::allocator > __cdecl agm::reflection::MethodBase::findMismatchedType0(s
truct agm::reflection::__callable__ *,const class type_info &,const class type_info &,const class type_info &)' : could not deduce template argument for 'param_size'
?? could not deduce template argument?? But it is specified ...
Did you forgot the <0> in findMismatchedType0<0> ??
|
|
|
|
|
Sorry i made a mistake!!!
Th result howevere is the same as before . It complains for that ">" !!
Maybe you are right and it seems a compiler bug.
|
|
|
|
|
If I can remeber correctly VC++ has some issues with handling white spaces in template declarations.
Try removing the spaces around "<" and ">". The code will look ugly but I have a feeling that it will compile.
|
|
|
|
|
Unfortunateliy that is not the problem.
The compiler still interprets it as a "lower than"!
|
|
|
|
|
The source zip has been updated. Let me know if this is better or worse in VC++
|
|
|
|
|
What is the secret to compile the library under gcc ????? It doesn't workkk !!!!!!!!!
Thanks in advance !
|
|
|
|
|
Hi,
Great job!
Could you please provide a makefile for gcc ?
I seem to have problems compiling the main.cpp...
Thanks!
|
|
|
|
|