[Boost-interest] C++ library for runtime-concepts (type-erasure)

Hello all. My name is Germán Diago and I'm been implementing a library for runtime concepts that I would like to submit to boost someday. It's a library that is targeting a way to be able to play well with boost.concept_check library, complementing it with the ability to hold those concepts in a runtime fashion. The target of the library is: -100% nonintrusive: -Being able to specify that a class models a concept without touching the class (via traits, not done yet). -Adapt via adl names of functions which don't match a concept for a class to be able to use that class as a concept. -Feel natural: being able as much as possible to convert from concept hierarchies as it's done for base and derived types. -Playing nicely with boost.concept_check. -Being able to specify that a class models more than one unrelated concept (via mpl::vector maybe). The features for the library, for now, just target movable and noncopyable objects, but I'll make it more general over time. I would like to hear feedback from all of you. Currently, the library can specify a runtime type that can hold objects modeling a concept. It's better to explain the workings of the library with an example, so here it goes: //Compile-time concepts namespace Concepts { template <class T> std::size_t getCapacityInMB(const T & t) { return t.getCapacityInMB(); } template <class T> void onOpen(T & t) { t.onOpen(); } template <class T> void onRemove(T & t) { t.onRemove(); } template <class T> struct Device { BOOST_CONCEPT_USAGE(Device) { t.getCapacityInMB(); } T t; static std::size_t getCapacityInMB(const T & v) { using Concepts::getCapacityInMB; return getCapacityInMB(v); } }; template <class T> struct PlugableDevice : Device<T> { BOOST_CONCEPT_USAGE(PlugableDevice) { plug_dev.onOpen(); plug_dev.onRemove(); } T plug_dev; static void onRemove(T & t) { using Concepts::onRemove; onRemove(t); } static void onOpen(T & t) { using Concepts::onOpen; onOpen(t); } }; } First, I must explain my runtime concept implementation as of now. We have a model and an interface class for each runtime concept we want to model. A concept is a class that is templated like this: template <class ConceptInterface, template <class> class Model, class BaseConcept = EmptyType, template <class> class ConceptCheckingClass = EmptyConcept> When we template this class with the ConceptInterface and with the model class, we can hold instances modeling that concept. Besides that, we can (optionally) enforce the compilance of our types with the compile-time concepts if we provide the concept checking class in the last template parameter. The template parameter BaseConcept specifies wether the concept refines another concept. This way it plays nicely with implicit conversions from derived-to-base. If a class inherits a concept, that concept will be inherited by the typedef. The storage for the class is held in the root of the hierarchy, and it always holds models for the most derived concept that a class models (though you have to tell the compiler which Concepts a class models) These are two classes covering two concepts (compile-time). We want to be able to hold unrelated instances modeling those concepts at runtime, so we can do something like this for both instances. //Runtime Concepts layer class IDeviceC { public: virtual std::size_t getCapacityInMB() const = 0; }; template <class T> class DeviceCModel : public MovableModelBase<T>, public IDeviceC { public: IMPLEMENT_MODEL_DEFAULT_MEMBERS(DeviceCModel) virtual std::size_t getCapacityInMB() const { return Concepts::Device<T>::getCapacityInMB(this->getData()); } }; typedef MovableConceptBase<IDeviceC, DeviceCModel, EmptyType, Concepts::Device> DeviceC; //Refined concept class IPlugableDeviceC : public IDeviceC { public: virtual void onOpen() = 0; virtual void onRemove() = 0; }; template <class T> class PlugableDeviceCModel : public MovableModelBase<T>, public IPlugableDeviceC { public: IMPLEMENT_MODEL_DEFAULT_MEMBERS(PlugableDeviceCModel) virtual void onOpen() { Concepts::PlugableDevice<T>::onOpen(this->getData()); } virtual std::size_t getCapacityInMB() const { Concepts::PlugableDevice<T>::getCapacityInMB(this->getData()); } virtual void onRemove() { Concepts::PlugableDevice<T>::onRemove(this->getData()); } }; //Create concept class that refines DeviceC, The 3rd parameter is the concept it refines typedef MovableConceptBase<IPlugableDeviceC, PlugableDeviceCModel, DeviceC, Concepts::PlugableDevice> PlugableDeviceC; Now we can provide a program with classes that model those concepts and try a little: class LegacyDevice : NonCopyable { public: //This class models DeviceC concept typedef DeviceC ModelOfType; std::size_t getCapacityInMB() const { return 10; } }; class IpodDevice : NonCopyable { public: //This class models PlugableDeviceC concept typedef PlugableDeviceC ModelOfType; void onOpen() { std::cout << "Opening Ipod device" << std::endl; } void onRemove() {} std::size_t getCapacityInMB() const { return 32 * 1024; } }; int main(int argc, char * argv[]) { std::vector<DeviceC> devices; IpodDevice ipod; LegacyDevice legacy; //devices.push_back(move(legacy_device)); devices.push_back(move(ipod)); devices.push_back(move(legacy)); DeviceC & dev_ref = devices[0]; std::cout << dev_ref->getCapacityInMB() << std::endl; for (auto & device : devices) { //device->onOpen(); std::cout << device->getCapacityInMB() << std::endl; } //TODO: Doesn't work downcasting because of the lvalue reference, buf dev_ref is actually holding a model that inherits the most-derived //PlugableDeviceC & pd = dynamic_cast<PlugableDeviceC&>(dev_ref); //pd->onOpen(); std::shared_ptr<DeviceC> dev_sptr(new PlugableDeviceC(IpodDevice())); std::cout << "Shared pointers:\n"; std::cout << (*dev_sptr)->getCapacityInMB() << std::endl; auto derived_ptr = dynamic_pointer_cast<PlugableDeviceC>(dev_sptr); (*derived_ptr)->onOpen(); IpodDevice & ipod_device = static_cast<IpodDevice&>(*derived_ptr); std::cout << "Ipod device back to concrete type: " << ipod_device.getCapacityInMB() << std::endl; std::cout << "Size of DeviceC " << sizeof(DeviceC) << std::endl; std::cout << "Size of PlugableDeviceC " << sizeof(PlugableDeviceC) << std::endl; std::cout << "The end" << std::endl; } You can see that conversions work, except for downcasting. The downcasting does not work because of an lvalue-ness problem, but if you instantiate a class like this: IpodDevice dev; DeviceC device(move(dev)); It will be holding an object modeling the PlugableDevice concept. The problem is that I cannot convert to a PlugableDeviceC because it's being held in a DeviceC, but the most-derived model is correctly instantiated. There are still things to do, but I feel they can be accomplished: -Downcasting: I can make a special type View<PlugableDeviceC> which can point to instances held in a DeviceC (maybe, don't know). -Generalize MovableConceptBase and MovableModelBase classes, so that you can use classes that are copyable, equality_comparable, etc. With these two pieces and maybe some improvements, I think I can provide a library that plays well with Boost.concept_check library and which is the runtime counterpart of it. Feedback is very welcome.

On 2/10/11 2:43 PM, "Germán Diago" <germandiago@gmail.com> wrote:
I think I can provide a library that plays well with Boost.concept_check library and which is the runtime counterpart of it. Feedback is very welcome.
I like where you are going.

2011/2/10 Daniel Larimer <dlarimer@gmail.com>:
On 2/10/11 2:43 PM, "Germán Diago" <germandiago@gmail.com> wrote:
I think I can provide a library that plays well with Boost.concept_check library and which is the runtime counterpart of it. Feedback is very welcome.
I like where you are going.
Thanks, I'll keep giving feedback.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Thu, Feb 10, 2011 at 2:43 PM, Germán Diago <germandiago@gmail.com> wrote:
Hello all. My name is Germán Diago and I'm been implementing a library for runtime concepts that I would like to submit to boost someday. It's a library that is targeting a way to be able to play well with boost.concept_check library, complementing it with the ability to hold those concepts in a runtime fashion.
Have you looked at http://stlab.adobe.com/group__poly__related.html and the associated research? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

I have posted Boost.IDL to github complete with documentation here: http://bytemaster.github.com/boost_idl/index.html https://github.com/bytemaster/boost_idl The library is header only. It is included as part of the Boost.Defrag "incubating" projects. The documentation includes several examples of how it is used to provide a simple 'command line interface' to a struct as well as a fully 'generic' RPC example that will expose any interface over the network using Boost.Serialization. Full RPC implementation 245 SLOC. The RPC example is very 'bare bones' because I think that a Boost.RPC library should be a separate project. I welcome any feedback. The code is still very 'new' and has not been tested on any platforms other than OS X, but it should all be very portable as I write Mac/Linux/Windows portable software every day. Server: struct Echo { std::string echo(const std::string &s) { return s; } }; BOOST_IDL_INTERFACE( Echo, BOOST_IDL_BASE, (echo) ) int main() { boost::idl::rpc_server<Echo> server( Echo() ); server.listen( 50001 ); return 0; } Client: struct Echo { std::string echo(const std::string &s); // implementation not needed }; BOOST_IDL_INTERFACE( Echo, BOOST_IDL_BASE, (echo) ) int main() { boost::idl::rpc_client<Echo> client; client.connect_to( "localhost", 50001 ); std::string s = client.echo( "what's up" ); return 0; } Type Erasure Applied to rpc_client: // erase the details of the rpc_client, by storing // it in a generic Echo interface. boost::idl::any<Echo> any_echo = client; Command Line Interface: template<typename InterfaceType,typename InterfaceDelegate> void start_cli( boost::idl::any<InterfaceType,InterfaceDelegate>& a ) { cli m_cli; m_cli.start_visit(a); std::string line; std::string cmd; std::string args; while( true ) { std::cerr << "Enter Method: "; std::getline( std::cin, line ); cmd = line.substr( 0, line.find('(') ); args = line.substr( cmd.size(), line.size() ); std::cerr << m_cli[cmd](args) << std::endl; } }

2011/2/14 Daniel Larimer <dlarimer@gmail.com>:
I have posted Boost.IDL to github complete with documentation here: http://bytemaster.github.com/boost_idl/index.html
https://github.com/bytemaster/boost_idl
The library is header only. It is included as part of the Boost.Defrag "incubating" projects.
The documentation includes several examples of how it is used to provide a simple 'command line interface' to a struct as well as a fully 'generic' RPC example that will expose any interface over the network using Boost.Serialization. Full RPC implementation 245 SLOC. The RPC example is very 'bare bones' because I think that a Boost.RPC library should be a separate project.
I welcome any feedback.
The code is still very 'new' and has not been tested on any platforms other than OS X, but it should all be very portable as I write Mac/Linux/Windows portable software every day. Server:
struct Echo { std::string echo(const std::string &s) { return s; } }; BOOST_IDL_INTERFACE( Echo, BOOST_IDL_BASE, (echo) )
int main() { boost::idl::rpc_server<Echo> server( Echo() ); server.listen( 50001 ); return 0; } Client:
struct Echo { std::string echo(const std::string &s); // implementation not needed }; BOOST_IDL_INTERFACE( Echo, BOOST_IDL_BASE, (echo) )
int main() { boost::idl::rpc_client<Echo> client; client.connect_to( "localhost", 50001 ); std::string s = client.echo( "what's up" ); return 0; }
Type Erasure Applied to rpc_client: // erase the details of the rpc_client, by storing // it in a generic Echo interface. boost::idl::any<Echo> any_echo = client;
Command Line Interface: template<typename InterfaceType,typename InterfaceDelegate> void start_cli( boost::idl::any<InterfaceType,InterfaceDelegate>& a ) { cli m_cli; m_cli.start_visit(a);
std::string line; std::string cmd; std::string args;
while( true ) { std::cerr << "Enter Method: "; std::getline( std::cin, line ); cmd = line.substr( 0, line.find('(') ); args = line.substr( cmd.size(), line.size() ); std::cerr << m_cli[cmd](args) << std::endl; } }
I haven't carefully read the documentation (sorry, have no time now), but I thought a lot about a new serialization library. My opinion is that this library couples two things together: interfaces and reflection. I think that the correct approach to this is: 1.- Build a general runtime concepts library (without reflection) 2.- Build a reflection mechanism that would be possible for every c++ type to use (non-intrusive). 3.- Build serialization and other reflection mechanisms in top of these two different libraries. I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects. My approach was to use a tuple that described every c++ member that a class had. It looked something like this: class MyClass { typedef MyClass this_class; std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; }; And the rest was done by a general serialize member function (actually a family with boost::enable_if). With c++0x I could pass the variable names in tuples if we had user-defined literals and constexpr (at least, I think so). With this info, it's very easy to serialize objects in c++ (although I didn't study every single problem like inheritance and so on). template <class T> std::string serialize(const T & t); With reflection for members and runtime concepts, a framework for RPC can be built on top of those general and useful by themselves library. I hope my opinion helped you. ______________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

2011/2/14 Daniel Larimer <dlarimer@gmail.com>:
I have posted Boost.IDL to github complete with documentation here: http://bytemaster.github.com/boost_idl/index.html
https://github.com/bytemaster/boost_idl
The library is header only. It is included as part of the Boost.Defrag "incubating" projects.
I haven't carefully read the documentation (sorry, have no time now), but I thought a lot about a new serialization library. My opinion is that this library couples two things together: interfaces and reflection.
I think that the correct approach to this is:
1.- Build a general runtime concepts library (without reflection) I would welcome such a solution; however, everything idea I have come up with in this regard requires either verbose/ugly macros or almost as much work as manually rolling your type erasure according to a well-defined
On 2/14/11 5:14 AM, "Germán Diago" <germandiago@gmail.com> wrote: pattern.
2.- Build a reflection mechanism that would be possible for every c++ type to use (non-intrusive).
If you do not mind C++0x dependency and verbose macros, Boost.Mirror does this very well. Older versions of Boost.Mirror do not require C++0x and the developers of Boost.Mirror are also creating a tool that will auto-generate the required macros. My feeling is that if your code requires that much reflection and you are willing to use a pre-processor then chances are your compile times and binary sizes will become huge. If you are using a pre-processor then you might as well generate code directly rather than using templates and should probably be using a different language. A simple version of run-time reflection, useful for serialization: This is the easy part, create a macro that does this: DEFINE_VISITOR( InterfaceType, (member, 1)(sequence,3,optional) ) template<typename VisitorType, typename ExtraProperties> void visit( Visitor& v, InterfaceType& i, const char* name, ExtraProperties prop ) { v.accept( i.member, "member", 0 ); v.accept( i.sequence, "sequence", 0 ) } The above works well for serialization, but loses the member pointer for reflection. So perhaps the following alternative would work: v.accept( i, &InterfaceType::member, "member", 0 ); I would hope that any reasonable compiler would cause the performance of both variations to be identical considering all of the information required is present. However, I suspect that the first version would probably involve one less 'indirection' and thus perform better for serialization operations, while the second would be better for reflection. Any type can use the BOOST_IDL_INTERFACE() macro to define its reflection without using it for type erasure.
3.- Build serialization and other reflection mechanisms in top of these two different libraries.
It is funny you mention this, I am actively working on adding serialization features to Boost.IDL with the goal of providing more control over the 'Archive' format than Boost.Serialization. Specifically, I want to support JSON / Protocol Buffer serialization approach to support forward/backward compatibility.
I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects.
My approach was to use a tuple that described every c++ member that a class had. It looked something like this:
class MyClass { typedef MyClass this_class;
std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; };
I suspect that your tuple approach could be combined with my visitor approach to offer two methods of reflection, runtime and compile time: DEFINE_MEMBERS( TYPE, (val_)(f_)...() ) typedef boost::fusion::vector< &TYPE::val_, &TYPE::f_, ... > TYPE ## MEMBERS The trouble is that even though we have compile time access to all of the member pointers, we have lost the 'name'. With some fancy magic to generate a const char* with external linkage one might be able to get the name into the template parameter as non-type template parameter. Even if you achieved complete static reflection with the above method, it would still not enable you to 'build' types with arbitrary member variables and methods. Perhaps using boost::fusion fused parameters you could simplify the number of permutations enough that it may be possible to generate a 'class' that given a method signature template parameter implements 'name' in terms of that signature. Correct me if I am wrong, but doesn't boost::fusion::vector<> explode compile times as the number of elements grows? Is tuple better? Would attempting to reflect an type with 50 fields in this manner be totally unfeasible?
And the rest was done by a general serialize member function (actually a family with boost::enable_if). With c++0x I could pass the variable names in tuples if we had user-defined literals and constexpr (at least, I think so). With this info, it's very easy to serialize objects in c++ (although I didn't study every single problem like inheritance and so on).
template <class T> std::string serialize(const T & t);
With reflection for members and runtime concepts, a framework for RPC can be built on top of those general and useful by themselves library.
I hope my opinion helped you.
Your ideas are good in theory and they are my ideal as well, but I have yet to reduce it to practice. Any ideas on that would be useful.
______________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

If you do not mind C++0x dependency and verbose macros, Boost.Mirror does this very well. Older versions of Boost.Mirror do not require C++0x and the developers of Boost.Mirror are also creating a tool that will auto-generate the required macros. My feeling is that if your code requires that much reflection and you are willing to use a pre-processor then chances are your compile times and binary sizes will become huge. If you are using a pre-processor then you might as well generate code directly rather than using templates and should probably be using a different language.
I looked at Boost.Mirror some time ago, but I think that, for my own goals, that is a too heavyweight dependency.
A simple version of run-time reflection, useful for serialization: It is funny you mention this, I am actively working on adding serialization features to Boost.IDL with the goal of providing more control over the 'Archive' format than Boost.Serialization. Specifically, I want to support JSON / Protocol Buffer serialization approach to support forward/backward compatibility.
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects.
My approach was to use a tuple that described every c++ member that a class had. It looked something like this:
class MyClass { typedef MyClass this_class;
std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; };
I suspect that your tuple approach could be combined with my visitor approach to offer two methods of reflection, runtime and compile time:
Yes, I think it could be possible. Generating the runtime information from the compile-time information is the right approach to not duplicate things. The only downside is that you still have to make some kind of registration for every type, but that could be as simple as a single macro.
The trouble is that even though we have compile time access to all of the member pointers, we have lost the 'name'. With some fancy magic to generate a const char* with external linkage one might be able to get the name into the template parameter as non-type template parameter.
With constexpr + user-defined literals, I think this can be done: template <char...C> struct Var_Name { //expand here C... }; And with user-defined literals: constexpr template <char... C> Var_Name<C...> operator _var(); now: //We didn't loose the name!!!! Good c++0x... typedef tuple<Var_Name<"name"_var>... This should be valid c++0x.
Even if you achieved complete static reflection with the above method, it would still not enable you to 'build' types with arbitrary member variables and methods. Perhaps using boost::fusion fused parameters you could simplify the number of permutations enough that it may be possible to generate a 'class' that given a method signature template parameter implements 'name' in terms of that signature.
I think that's not possible in c++, but I'll try to investigate once I have some time.
Correct me if I am wrong, but doesn't boost::fusion::vector<> explode compile times as the number of elements grows? Is tuple better? Would attempting to reflect an type with 50 fields in this manner be totally unfeasible?
I haven't tried those tests, but maybe it would take too long. It's just the idea I was implementing and that I had in my mind, but I don't know wether its compile-times are practical.
Your ideas are good in theory and they are my ideal as well, but I have yet to reduce it to practice. Any ideas on that would be useful.
So, to summarize, we need: -Static Type information -> Useful for serialization (I think that boost.Serialization library is aging in this regard, although very useful still today). I would try with a tuple trait approach. -Type erasure. -> I'm trying to implement this one, and I think a nice library can be built in c++/c++0x. -RPC. -> This could be based in information registered for functions through metaprogramming and pointer to member registration. - Enable 'building' types with arbitrary member variables. -> This one is pretty difficult.

On 2/14/11 1:36 PM, "Germán Diago" <germandiago@gmail.com> wrote:
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
What do those who are more experienced with Boost.Serialization have to say about the future of that library? What direction is Boost.Serialization going? It seems to me that Boost.Serialization is only compatible with itself and even though it can 'read/write' to/from a XML or even a 'json' file, it gives you very little control over the resultant structure of the file, because it throws in version info, object graphs, etc. So attempting to implement a JSON RPC built on Boost.Serialization is difficult if you do not control both sides of the RPC. Another example would be implementing a binary RPC protocol that must communicate with an embedded device that only supports C. It would be very difficult to craft specific byte streams from structs without knowing the internals of Boost.Serialization. It appears that the only option at the moment is to implement your own Archive. Dan

On 02/14/11 14:17, Daniel Larimer wrote:
It seems to me that Boost.Serialization is only compatible with itself and even though it can 'read/write' to/from a XML or even a 'json' file, it gives you very little control over the resultant structure of the file, because it throws in version info, object graphs, etc. So attempting to implement a JSON RPC built on Boost.Serialization is difficult if you do not control both sides of the RPC.
Another example would be implementing a binary RPC protocol that must communicate with an embedded device that only supports C. It would be very difficult to craft specific byte streams from structs without knowing the internals of Boost.Serialization. It appears that the only option at the moment is to implement your own Archive.
Dan
I've used Boost.Serialization to implement several network interfaces where I had no control over the protocol format and had to craft an Archive class to adhere to the given standard. In my experience, this approach has been much cleaner and simpler than trying to write the marshaling code in each object. It's paid dividends when I have needed to save an object and can use the default text or xml Archives. The Serialization library has a macro |BOOST_CLASS_IMPLEMENTATION(my_class, boost::serialization::||object_serializable||) that will serialize the class using the serialize() function but add no extra class or version information. In this case, you know exactly what the serialized byte stream will look like at the expense of having to write a simple Archive class Brian|

On Mon, Feb 14, 2011 at 8:17 PM, Daniel Larimer <dlarimer@gmail.com> wrote:
On 2/14/11 1:36 PM, "Germán Diago" <germandiago@gmail.com> wrote:
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
What do those who are more experienced with Boost.Serialization have to say about the future of that library? What direction is Boost.Serialization going?
I certainly am no expert on Boost.Serialization but I've written two or three serialization/marshaling utilities and I've played a little with boost.Serialization in the past.
It seems to me that Boost.Serialization is only compatible with itself and even though it can 'read/write' to/from a XML or even a 'json' file, it gives you very little control over the resultant structure of the file, because it throws in version info, object graphs, etc. So attempting to implement a JSON RPC built on Boost.Serialization is difficult if you do not control both sides of the RPC.
Another example would be implementing a binary RPC protocol that must communicate with an embedded device that only supports C. It would be very difficult to craft specific byte streams from structs without knowing the internals of Boost.Serialization. It appears that the only option at the moment is to implement your own Archive.
As I've already written on the other thread, something like this can be completely reflection-based and the Mirror library will implement a manipulator generator tool similar to the already available factory generator. The user will have to provide special templates saying how to handle member variables with 'atomic' types like int, float, string, etc., how to (generically) handle structured types and containers, and how to handle enums. The generator then will create a manipulator based on the reflected meta-data and the user specific code. There are basically two things I need to resolve before starting the work on this: 1) some good abstraction for container reflection 2) object tracking Matus

On 14/02/11 18:36, Germán Diago wrote:
With constexpr + user-defined literals, I think this can be done:
template <char...C> struct Var_Name { //expand here C... };
And with user-defined literals:
constexpr template <char... C> Var_Name<C...> operator _var();
now:
//We didn't loose the name!!!! Good c++0x... typedef tuple<Var_Name<"name"_var>...
This should be valid c++0x.
Alas, I think not. In my reading of the standard (N3092, [lex.ext]), only integer literals and floating point literals support the literal operator template form (which is what you're trying to use here); for string literals you only get the form operator "" X(char*, size_t); which is no good for compile-time lookup because it doesn't give compile-time access to the chars. Hoping I'm wrong, John Bytheway

On Mon, Feb 14, 2011 at 7:36 PM, Germán Diago <germandiago@gmail.com> wrote:
If you do not mind C++0x dependency and verbose macros, Boost.Mirror does this very well. Older versions of Boost.Mirror do not require C++0x and the developers of Boost.Mirror are also creating a tool that will auto-generate the required macros. My feeling is that if your code requires that much reflection and you are willing to use a pre-processor then chances are your compile times and binary sizes will become huge. If you are using a pre-processor then you might as well generate code directly rather than using templates and should probably be using a different language.
I looked at Boost.Mirror some time ago, but I think that, for my own goals, that is a too heavyweight dependency.
This certainly may seem so from the point of view of your library. But if you look at the bigger picture then you'll see that it will be many times used in applications using other utilities and libraries, some of which could also employ reflection, and then having a single reflection facility that can provide meta-data for all of them is a great advantage. The slight overhead of the compile-time part of Mirror compared to what you are proposing is IMO worth it. The reusability of meta-data provided by Mirror is one of its strong suits, if I may say so :)
A simple version of run-time reflection, useful for serialization: It is funny you mention this, I am actively working on adding serialization features to Boost.IDL with the goal of providing more control over the 'Archive' format than Boost.Serialization. Specifically, I want to support JSON / Protocol Buffer serialization approach to support forward/backward compatibility.
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
This is what the visitors in the old (non C++0x) version of Mirror were doing. In the new version this will be implemented by special manipulator classes that will be generated by a mechanism similar to the factory generator that already is in Mirror. This way you will be able to do not only serialization/marshaling-like things but you'll be able to generate a (reusable) GUI for the inspection or even manipulation of existing instances of every 'reflectible' type.
I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects.
My approach was to use a tuple that described every c++ member that a class had. It looked something like this:
If you need just this I think you can use Boost.Fusion. But, the above still applies. It focuses on a single task what makes the meta-data unusable for some other purposes.
class MyClass { typedef MyClass this_class;
std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; };
[snip]
The trouble is that even though we have compile time access to all of the member pointers, we have lost the 'name'. With some fancy magic to generate a const char* with external linkage one might be able to get the name into the template parameter as non-type template parameter.
With constexpr + user-defined literals, I think this can be done:
template <char...C> struct Var_Name { //expand here C... };
And with user-defined literals:
constexpr template <char... C> Var_Name<C...> operator _var();
now:
//We didn't loose the name!!!! Good c++0x... typedef tuple<Var_Name<"name"_var>...
I've tried to use compile-time strings with Mirror twice, the first time with MPL and the second time with C++0x variadic templates, and the result was an increase in both compile-times and executable size (somewhere between 3 to 7 percent depending on the usage). Unless you really, really need to use a compile time string, consider using a simple literal.
This should be valid c++0x.
Even if you achieved complete static reflection with the above method, it would still not enable you to 'build' types with arbitrary member variables and methods. Perhaps using boost::fusion fused parameters you could simplify the number of permutations enough that it may be possible to generate a 'class' that given a method signature template parameter implements 'name' in terms of that signature.
I think that's not possible in c++, but I'll try to investigate once I have some time.
[snip]
- Enable 'building' types with arbitrary member variables. -> This one is pretty difficult.
I'm not sure if I understand correctly what you mean but if you are referring to transforming something like this... struct some_type { T1 m1; T2 m2; ... Tn mn; }; into struct some_other_type { transformed<meta_data<T1, m1> >::type m1; transformed<meta_data<T2, m2> >::type m2; ... transformed<meta_data<Tn, mn> >::type mn; }; then it will be doable with Mirror (it actually already is in the old version and partially also in the new one but still undocumented). BR, Matus

I looked at Boost.Mirror some time ago, but I think that, for my own goals, that is a too heavyweight dependency.
This certainly may seem so from the point of view of your library. But if you look at the bigger picture then you'll see that it will be many times used in applications using other utilities and libraries, some of which could also employ reflection, and then having a single reflection facility that can provide meta-data for all of them is a great advantage. The slight overhead of the compile-time part of Mirror compared to what you are proposing is IMO worth it. The reusability of meta-data provided by Mirror is one of its strong suits, if I may say so :)
I think you're right. I can reconsider my decision, but for now I'll be trying to improve my design on type erasure. Once that is done, the only thing left is to choose how to generate reflection information. My top priority is not to be intrusive if that can be achieved.
A simple version of run-time reflection, useful for serialization: It is funny you mention this, I am actively working on adding serialization features to Boost.IDL with the goal of providing more control over the 'Archive' format than Boost.Serialization. Specifically, I want to support JSON / Protocol Buffer serialization approach to support forward/backward compatibility.
I think that Boost.serialization library is a good library, but if it were written nowadays, it would be done in another way. I think that the correct way when c++0x is implemented with some trait that identifies the members that you want to serialize, and, after that, return an in-memory object, like a string. Having the information provided by those members, you could implement generic and custom serializations: binary, json, and whatever, without having to code a special-purpose format for your specific library. This way we can make libraries useful to more people.
This is what the visitors in the old (non C++0x) version of Mirror were doing. In the new version this will be implemented by special manipulator classes that will be generated by a mechanism similar to the factory generator that already is in Mirror.
This way you will be able to do not only serialization/marshaling-like things but you'll be able to generate a (reusable) GUI for the inspection or even manipulation of existing instances of every 'reflectible' type.
This sounds great.
I tried (but it's incomplete) a new reflection approach, and I think that with c++0x will be possible. The goal for this reflection library was serialization, so it wasn't a general reflection framework, but it was good enough to serialize objects.
My approach was to use a tuple that described every c++ member that a class had. It looked something like this:
If you need just this I think you can use Boost.Fusion. But, the above still applies. It focuses on a single task what makes the meta-data unusable for some other purposes.
Ok. The correct way is to reuse libraries as much as possible so that bugs can be corrected always in the same place. But at the same time I would like a syntax that avoids macros as much as possible. For example, my std::tuple inside MyClass uses a macro, but a very obvious one. The rest is understandable. There are many ways to write complicated macros, so I try to avoid them except when there is no other practical way.
class MyClass { typedef MyClass this_class;
std::string val_; float f_; public: typedef std::tuple<MEM_VARS2(val_, f_)> serializable_members_t; };
[snip]
The trouble is that even though we have compile time access to all of the member pointers, we have lost the 'name'. With some fancy magic to generate a const char* with external linkage one might be able to get the name into the template parameter as non-type template parameter.
With constexpr + user-defined literals, I think this can be done:
template <char...C> struct Var_Name { //expand here C... };
And with user-defined literals:
constexpr template <char... C> Var_Name<C...> operator _var();
now:
//We didn't loose the name!!!! Good c++0x... typedef tuple<Var_Name<"name"_var>...
I've tried to use compile-time strings with Mirror twice, the first time with MPL and the second time with C++0x variadic templates, and the result was an increase in both compile-times and executable size (somewhere between 3 to 7 percent depending on the usage). Unless you really, really need to use a compile time string, consider using a simple literal.
Even if that's true, I think that if compile times don't grow much, compile-time strings should be the right way to put string information. I've tried much and very hard over time, and this avoids my hated macros a lot (with c++0x).
This should be valid c++0x.
Even if you achieved complete static reflection with the above method, it would still not enable you to 'build' types with arbitrary member variables and methods. Perhaps using boost::fusion fused parameters you could simplify the number of permutations enough that it may be possible to generate a 'class' that given a method signature template parameter implements 'name' in terms of that signature.
I think that's not possible in c++, but I'll try to investigate once I have some time.
[snip]
- Enable 'building' types with arbitrary member variables. -> This one is pretty difficult.
I'm not sure if I understand correctly what you mean but if you are referring to transforming something like this...
struct some_type { T1 m1; T2 m2; ... Tn mn; };
That was a goal of Boost.IDL interfaces, but I tried to make a summary of what would be useful to take into account to design things that don't overlap.
then it will be doable with Mirror (it actually already is in the old version and partially also in the new one but still undocumented).
I'll consider using Boost.Mirror. In fact, it would be *the right way* to add services that use reflection, such as serialization. But, you know, I want to avoid macros as much as possible (except when registering runtime information, which I think it can't be done in other way). So I would like to find some way to non-intrusively (like iterator_traits) add compile-time information for my classes.
BR,
Matus _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 2/15/11 4:58 AM, "Germán Diago" <germandiago@gmail.com> wrote:
I'm not sure if I understand correctly what you mean but if you are referring to transforming something like this...
struct some_type { T1 m1; T2 m2; ... Tn mn; };
That was a goal of Boost.IDL interfaces, but I tried to make a summary of what would be useful to take into account to design things that don't overlap.
then it will be doable with Mirror (it actually already is in the old version and partially also in the new one but still undocumented).
Color me very interested in how you achieved this. Though what I would really like to see is: struct some_type { std::string append( std::string, double ); }; Converted Into functionally equivalent => struct new_some_type { future<string> append( string, double ) { future<string> fut; m_socket->async_sendto( serialize( s, d ), host, boost::bind(wait_for_response, fut ); return fut; } }; Or converted Into => struct some_new_type { function<string(string,double)> append; }; Using just your Mirror mirror macros + templates? I am very impressed with Mirror, but its dependency on C++0x features that are not available in MSVC is almost a non-starter for me. Particularly because even though gcc supports much of C++0x, Mac OS X Development Tools still comes bundled with gcc 4.2.1 which does not support ANY C++0x. If you can show an example of how mirror would accomplish that, I will have to reconsider my approach to Type Erasure, RPC, and serialization. What is the status of Mirror's review for inclusion in official Boost?

On Tue, Feb 15, 2011 at 3:34 PM, Daniel Larimer <dlarimer@gmail.com> wrote:
On 2/15/11 4:58 AM, "Germán Diago" <germandiago@gmail.com> wrote:
I'm not sure if I understand correctly what you mean but if you are referring to transforming something like this...
struct some_type { T1 m1; T2 m2; ... Tn mn; };
That was a goal of Boost.IDL interfaces, but I tried to make a summary of what would be useful to take into account to design things that don't overlap.
then it will be doable with Mirror (it actually already is in the old version and partially also in the new one but still undocumented).
Color me very interested in how you achieved this. Though what I would really like to see is:
Basically the Mirror's registering macros create the following two helper structures for every member variable: template <typename X> struct _by_name_typ { typedef X member_variable_name; }; template <typename X> struct _by_name_val { X member_variable_name; }; then Mirror let's you choose the type(s) for X and compose them into a single class via multiple inheritance. Currently only the 'by_name' template class uses this to allow you to get access to member variable meta-data via its name at compile time (although I could not find too many use cases where this is really necessary to do :))
struct some_type { std::string append( std::string, double ); };
Converted Into functionally equivalent =>
struct new_some_type { future<string> append( string, double ) { future<string> fut; m_socket->async_sendto( serialize( s, d ), host, boost::bind(wait_for_response, fut ); return fut; } };
This is doable. Mirror does not implement it yet but during the work on my master's thesis I've implemented a simple RPC mechanism that did something very similar to the above using reflection.
Or converted Into =>
struct some_new_type { function<string(string,double)> append; };
Hmm, I've never considered turning a function into a member variable but from the top of my head I don't see why this would not work by using some variation of the approach described above (well maybe overloads could cause some trouble...)
Using just your Mirror mirror macros + templates?
I am very impressed with Mirror, but its dependency on C++0x features that are not available in MSVC is almost a non-starter for me. Particularly because even though gcc supports much of C++0x, Mac OS X Development Tools still comes bundled with gcc 4.2.1 which does not support ANY C++0x.
Thank you and, yes, this is a problem, but I hope that other compilers besides GCC will implement C++0x after the final vote in March, many are already working on it. Anyway I believe the transition from C++98 to C++0x was worth it. In pre-C++0x I've spent more time struggling with the compilers to do basic things that now work perfectly. I do a lot of Windows programming myself and in projects using Mirror I'm stuck with Cygwin so getting Mirror going in MSVC is also one of my priorities.
If you can show an example of how mirror would accomplish that, I will have to reconsider my approach to Type Erasure, RPC, and serialization.
What is the status of Mirror's review for inclusion in official Boost?
There are several things currently preventing me from submitting Mirror for review: 1) As already discussed above it is not (yet) portable because of the lack of support for C++0x by the compilers 2) Expectation of breaking changes. I'm not going to submit the library for review until I'm at least 95 percent sure that there will be no breaking changes in the existing things. Now I'm somewhere around 70% :) 3) Few things to finish (like the manipulator generator mentioned before, the transformations discussed above and some others) 4) Documentation 5) Missing unit-tests As for a specific date, I've already made so many promises to various people about the submission for review that even I consider myself a liar now :) so I've stopped doing that. BR, Matus

I think I may have a solution for defining erasures with the total "cost" of a virtual method invocation and the memory model of boost::any. DEFINE_ERASURE( Calculator, (add)(sub), virtual double add(double) = 0; virtual double sub(double) = 0; ) Details are provided in the discussion below. On Feb 15, 2011, at 11:58 AM, Matus Chochlik wrote:
On Tue, Feb 15, 2011 at 3:34 PM, Daniel Larimer <dlarimer@gmail.com> wrote:
On 2/15/11 4:58 AM, "Germán Diago" <germandiago@gmail.com> wrote:
I'm not sure if I understand correctly what you mean but if you are referring to transforming something like this...
struct some_type { T1 m1; T2 m2; ... Tn mn; };
That was a goal of Boost.IDL interfaces, but I tried to make a summary of what would be useful to take into account to design things that don't overlap.
then it will be doable with Mirror (it actually already is in the old version and partially also in the new one but still undocumented).
Color me very interested in how you achieved this. Though what I would really like to see is:
Basically the Mirror's registering macros create the following two helper structures for every member variable:
template <typename X> struct _by_name_typ { typedef X member_variable_name; };
template <typename X> struct _by_name_val { X member_variable_name; };
That was essentially my approach in Boost.IDL (New name suggestions?)
then Mirror let's you choose the type(s) for X and compose them into a single class via multiple inheritance. Currently only the 'by_name' template class uses this to allow you to get access to member variable meta-data via its name at compile time (although I could not find too many use cases where this is really necessary to do :))
struct some_type { std::string append( std::string, double ); };
Converted Into functionally equivalent =>
struct new_some_type { future<string> append( string, double ) { future<string> fut; m_socket->async_sendto( serialize( s, d ), host, boost::bind(wait_for_response, fut ); return fut; } };
This is doable. Mirror does not implement it yet but during the work on my master's thesis I've implemented a simple RPC mechanism that did something very similar to the above using reflection.
Doable you say.. Perhaps, but at what cost? Unlike member variables, there are a huge number of permutations that must be supported for each name that you wish to consider. template<typename Signature, bool IsConst=false, bool IsVirtual=false, bool isStatic=false> struct _by_name_method{} template<typename OnClass, RTN(ARG1,...)> struct _by_name_method : virtual public OnClass { RTN some_name(ARG1,...) { return static_cast<OnClass*>(this)->impl->some_name(ARG1,...) } } Then you run into the problem of specifying the implementation of each method in terms of the object they are being composed on to. In the example above I show an example using virtual inheritance and require that OnClass provide impl->name(args), this effectively just moved our problem. Applied to type erasure: class TypeErasure { public: template<typename ModelImpl> TypeErasure( ModelImpl m ) { impl = new Model<ModelImpl>(); } RTN some_name(ARGS...) { impl->some_name(); } private: struct Concept { virtual RTN some_name(ARGS...) = 0; }; template<typename M> struct Model : public M, public Concept {}; }; You need to define the method some_name() two different times, once in the concept and once in the TypeErasure. You would need to do something like this: template<typename VirtualBase, typename RTN(ARG1,...)> struct _by_name_method : VirtualBase { RTN some_name(ARG1,...) { return ((VirtualBase*)this)->some_name(args...); } } So I suppose that if you did not mind creating 4 x (MAX PARAM) template specializations PER NAME to allow for const/nonconst virtual/nonvirtual overrides, then it would be ok. I guess, with veridic templates (which I am not familiar with due to lack of compiler support), this whole issue might go away. In my alternative of converting methods into function<Signature> member variables, this "implementation" is dynamically provided by generating a suitable function object in the visitor. I guess with the approach outlined above you could achieve the following "automatic TypeErasure" generation: DEFINE_ERASURE( Calculator, (add)(sub), virtual double add(double) = 0; virtual double sub(double) = 0; ) Implemented as something like: #define DEFINE_ERASURE( NAME, METHOD_SEQ, ... ) namespace detail { namespace NAME { namespace methods { SEQ_FOR_EACH( DEFINE_BY_NAME_METHOD ) } struct Concept { __VA_ARGS__ }; } } class NAME : SEQ_FOR_EACH( INHERIT_BY_NAME_METHOD ) { public: template<typename CONCEPT> NAME( CONCEPT c ) :impl( new Model<CONCEPT>(c) ){} protected: scoped_ptr<Concept> impl; private: template<typename M> struct Model : public M, public detail::NAME::Concept {} }; To improve performance on non-variadic template supporting compilers, you could specify the number of parameters like so: DEFINE_ERASURE( Calculator, ((add,1))((sub,3)), virtual double add(double) = 0; virtual double sub(double,int,string) = 0; ) So my quick reply turned into a brainstorm dump. Hopefully the ideas are useful. I would like feedback on how such an implementation would be received by the community. I suspect that this would be the most efficient solution, but it would still fail to provide some of the benefits of my member function object solution, specifically, generating RPC client stubs or scripting engine hooks or any other task that requires "per-method" data. The method also forces you to list every method twice, once in the erasure and once in your type that implements the erasure. In situations such as building an RPC server, you only want to define the class once, then expose it with as little redundant information as possible. So I suspect that there is probably room for both types of erasure.
Or converted Into =>
struct some_new_type { function<string(string,double)> append; };
Hmm, I've never considered turning a function into a member variable but from the top of my head I don't see why this would not work by using some variation of the approach described above (well maybe overloads could cause some trouble...)
Using just your Mirror mirror macros + templates?
I am very impressed with Mirror, but its dependency on C++0x features that are not available in MSVC is almost a non-starter for me. Particularly because even though gcc supports much of C++0x, Mac OS X Development Tools still comes bundled with gcc 4.2.1 which does not support ANY C++0x.
Thank you and, yes, this is a problem, but I hope that other compilers besides GCC will implement C++0x after the final vote in March, many are already working on it. Anyway I believe the transition from C++98 to C++0x was worth it. In pre-C++0x I've spent more time struggling with the compilers to do basic things that now work perfectly.
I do a lot of Windows programming myself and in projects using Mirror I'm stuck with Cygwin so getting Mirror going in MSVC is also one of my priorities.
If you can show an example of how mirror would accomplish that, I will have to reconsider my approach to Type Erasure, RPC, and serialization.
What is the status of Mirror's review for inclusion in official Boost?
There are several things currently preventing me from submitting Mirror for review:
1) As already discussed above it is not (yet) portable because of the lack of support for C++0x by the compilers
2) Expectation of breaking changes. I'm not going to submit the library for review until I'm at least 95 percent sure that there will be no breaking changes in the existing things. Now I'm somewhere around 70% :)
3) Few things to finish (like the manipulator generator mentioned before, the transformations discussed above and some others)
4) Documentation
5) Missing unit-tests
As for a specific date, I've already made so many promises to various people about the submission for review that even I consider myself a liar now :) so I've stopped doing that.
BR,
Matus _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Tue, Feb 15, 2011 at 9:38 PM, Daniel Larimer <dlarimer@gmail.com> wrote:
I think I may have a solution for defining erasures with the total "cost" of a virtual method invocation and the memory model of boost::any.
DEFINE_ERASURE( Calculator, (add)(sub), virtual double add(double) = 0; virtual double sub(double) = 0; )
Details are provided in the discussion below.
[snip/]
Color me very interested in how you achieved this. Though what I would really like to see is:
Basically the Mirror's registering macros create the following two helper structures for every member variable:
template <typename X> struct _by_name_typ { typedef X member_variable_name; };
template <typename X> struct _by_name_val { X member_variable_name; };
That was essentially my approach in Boost.IDL (New name suggestions?)
I came up with the idea when I was playing with Loki's typelists and class generators so in the old version of Mirror the tool which did that transformation described above was also called a glass generator (but it's an ugly name for a library)
then Mirror let's you choose the type(s) for X and compose them into a single class via multiple inheritance. Currently only the 'by_name' template class uses this to allow you to get access to member variable meta-data via its name at compile time (although I could not find too many use cases where this is really necessary to do :))
struct some_type { std::string append( std::string, double ); };
Converted Into functionally equivalent =>
struct new_some_type { future<string> append( string, double ) { future<string> fut; m_socket->async_sendto( serialize( s, d ), host, boost::bind(wait_for_response, fut ); return fut; } };
This is doable. Mirror does not implement it yet but during the work on my master's thesis I've implemented a simple RPC mechanism that did something very similar to the above using reflection.
Doable you say.. Perhaps, but at what cost? Unlike member variables, there are a huge number of permutations that must be supported for each name that you wish to consider.
template<typename Signature, bool IsConst=false, bool IsVirtual=false, bool isStatic=false> struct _by_name_method{}
template<typename OnClass, RTN(ARG1,...)> struct _by_name_method : virtual public OnClass { RTN some_name(ARG1,...) { return static_cast<OnClass*>(this)->impl->some_name(ARG1,...) } }
This is similar to how the RPC that I mentioned was implemented. It was pre-C++0x so it depended heavily on preprocessor tricks and recursive type-lists. I think that with variadic templates it can be implemented more 'nicely'.
Then you run into the problem of specifying the implementation of each method in terms of the object they are being composed on to. In the example above I show an example using virtual inheritance and require that OnClass provide impl->name(args), this effectively just moved our problem.
Applied to type erasure:
class TypeErasure { public: template<typename ModelImpl> TypeErasure( ModelImpl m ) { impl = new Model<ModelImpl>(); }
RTN some_name(ARGS...) { impl->some_name(); }
private: struct Concept { virtual RTN some_name(ARGS...) = 0; }; template<typename M> struct Model : public M, public Concept {}; };
You need to define the method some_name() two different times, once in the concept and once in the TypeErasure.
You would need to do something like this: template<typename VirtualBase, typename RTN(ARG1,...)> struct _by_name_method : VirtualBase { RTN some_name(ARG1,...) { return ((VirtualBase*)this)->some_name(args...); } }
So I suppose that if you did not mind creating 4 x (MAX PARAM) template specializations PER NAME to allow for const/nonconst virtual/nonvirtual overrides, then it would be ok. I guess, with veridic templates (which I am not familiar with due to lack of compiler support), this whole issue might go away.
This is basically how I plan to do it, although I'm considering to use wrapped member pointers. There are some tradeoffs I'll have to write some code using both approaches and compare them. I think that to do the type erasure you would create an abstract interface for the Model. You would register it with Mirror which would create the _by_name_mem_fn wrappers and then use some template meta-programming to create a class using the Model as an interface and derive from the individual _by_name_mem_fn instantiations which would implement the individual member functions.
In my alternative of converting methods into function<Signature> member variables, this "implementation" is dynamically provided by generating a suitable function object in the visitor.
I guess with the approach outlined above you could achieve the following "automatic TypeErasure" generation:
DEFINE_ERASURE( Calculator, (add)(sub), virtual double add(double) = 0; virtual double sub(double) = 0; )
Implemented as something like:
#define DEFINE_ERASURE( NAME, METHOD_SEQ, ... ) namespace detail { namespace NAME { namespace methods { SEQ_FOR_EACH( DEFINE_BY_NAME_METHOD ) } struct Concept { __VA_ARGS__ }; } } class NAME : SEQ_FOR_EACH( INHERIT_BY_NAME_METHOD ) { public: template<typename CONCEPT> NAME( CONCEPT c ) :impl( new Model<CONCEPT>(c) ){}
protected: scoped_ptr<Concept> impl; private: template<typename M> struct Model : public M, public detail::NAME::Concept {} };
To improve performance on non-variadic template supporting compilers, you could specify the number of parameters like so: DEFINE_ERASURE( Calculator, ((add,1))((sub,3)), virtual double add(double) = 0; virtual double sub(double,int,string) = 0; )
So my quick reply turned into a brainstorm dump. Hopefully the ideas are useful. I would like feedback on how such an implementation would be received by the community.
I suspect that this would be the most efficient solution, but it would still fail to provide some of the benefits of my member function object solution, specifically, generating RPC client stubs or scripting engine hooks or any other task that requires "per-method" data.
The method also forces you to list every method twice, once in the erasure and once in your type that implements the erasure. In situations such as building an RPC server, you only want to define the class once, then expose it with as little redundant information as possible. So I suspect that there is probably room for both types of erasure.
[snip/] Matus

On Tue, Feb 15, 2011 at 10:58 AM, Germán Diago <germandiago@gmail.com> wrote: [snip]
Ok. The correct way is to reuse libraries as much as possible so that bugs can be corrected always in the same place. But at the same time I would like a syntax that avoids macros as much as possible. For example, my std::tuple inside MyClass uses a macro, but a very obvious one. The rest is understandable. There are many ways to write complicated macros, so I try to avoid them except when there is no other practical way.
I've added two new templates to Mirror that replace the type reflection macros: So now instead of using MIRRORED_TYPE(X), MIRRORED_CLASS(X), ... you can use either the mirror::reflected_type<X> or the mirror::reflected<X> template. Thell be available in the next release or you can get the current version via GIT. mirror::reflected_type<X> *is a* type conforming to the MetaType concept and mirror::reflected<X>::type *returns a* type conforming to the MetaType concept. More precisely these templates provide you with types conforming to either MetaType, MetaClass or MetaEnum, depending on how the type X was registered with Mirror. You can use the categorize_meta_object() function or the meta_object_category<> template to get a tag type for tag dispatching between there concepts. See the following three examples for comparison: http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/mirror_2example_2typenam... http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/mirror_2example_2typenam... http://kifri.fri.uniza.sk/~chochlik/mirror-lib/html/mirror_2example_2typenam... I'll add a few more or update the existing examples in the near future. This way you can avoid using macros when reflecting types. I still believe that using macros for the registering is the right thing to do, even with all the problems of preprocessor macros. [snip/] Matus

Have you looked at http://stlab.adobe.com/group__poly__related.html and the associated research?
Yes, it was my main source of inspiration.
participants (6)
-
Brian Poole
-
Daniel Larimer
-
Dave Abrahams
-
Germán Diago
-
John Bytheway
-
Matus Chochlik