[fusion] BOOST_FUSION_DEFINE_STRUCT with user defined methods
Hi, I often use BOOST_FUSION_DEFINE_STRUCT not to generate a fusion-sequence per se, but to get a struct with - default initialisation for all members - a reasonable set of constructors - equality-check - all above without additional code But sometimes I would like to have additional methods in those structs, but deriving from those or fusion-adapting them loses at least one of the nice properties above. After looking at the BOOST_FUSION_DEFINE_STRUCT implementation I though about splitting the makro BOOST_FUSION_DEFINE_STRUCT_IMPL an inject my code in-between. Now my questions are: - Is there anything I've overseen and might detroy some fusion-mechanism? - Is there any chance to get macros like BOOST_FUSION_DEFINE_STRUCT_[BEGIN|END] (and also for the other BOOST_FUSION_DEFINE_... macros? Tobias -- View this message in context: http://boost.2283326.n4.nabble.com/fusion-BOOST-FUSION-DEFINE-STRUCT-with-us... Sent from the Boost - Users mailing list archive at Nabble.com.
On 8/27/14, 2:07 PM, Tobias Loew wrote:
Hi,
I often use BOOST_FUSION_DEFINE_STRUCT not to generate a fusion-sequence per se, but to get a struct with
- default initialisation for all members - a reasonable set of constructors - equality-check - all above without additional code
But sometimes I would like to have additional methods in those structs, but deriving from those or fusion-adapting them loses at least one of the nice properties above. After looking at the BOOST_FUSION_DEFINE_STRUCT implementation I though about splitting the makro BOOST_FUSION_DEFINE_STRUCT_IMPL an inject my code in-between. Now my questions are:
- Is there anything I've overseen and might detroy some fusion-mechanism? - Is there any chance to get macros like BOOST_FUSION_DEFINE_STRUCT_[BEGIN|END] (and also for the other BOOST_FUSION_DEFINE_... macros?
The only problem I see is that the mechanism is private and is not guaranteed to remain unchanged. Actually there's work in progress cleaning up the macros and the implementation by Damien Buhl. CC'ing him now. Your thoughts, Damien? Regards, -- Joel de Guzman http://www.ciere.com http://boost-spirit.com http://www.cycfi.com/
Hi Joel and Tobias, Sorry I wasn't on Boost Users, I was only looking at devel, but now it's done. Thank you Joel for forwarding. My replies below : On 08/28/2014 05:09 AM, Joel de Guzman wrote:
On 8/27/14, 2:07 PM, Tobias Loew wrote:
Hi,
I often use BOOST_FUSION_DEFINE_STRUCT not to generate a fusion-sequence per se, but to get a struct with
- default initialisation for all members - a reasonable set of constructors - equality-check - all above without additional code
But sometimes I would like to have additional methods in those structs, but deriving from those or fusion-adapting them loses at least one of the nice properties above. After looking at the BOOST_FUSION_DEFINE_STRUCT implementation I though about splitting the makro BOOST_FUSION_DEFINE_STRUCT_IMPL an inject my code in-between. Now my questions are:
- Is there anything I've overseen and might detroy some fusion-mechanism? - Is there any chance to get macros like BOOST_FUSION_DEFINE_STRUCT_[BEGIN|END] (and also for the other BOOST_FUSION_DEFINE_... macros?
Actually I'm not so much a fan of the DEFINE_STRUCT macros in their current state, and I would prefer something new (just thinking outloud) like this : ```cpp BOOST_FUSION_ADAPT_STRUCT( { add_constructors=true, default_initialize_members=true }, (struct mystruct { public: int i; int member2; })); ``` Which would use the same techniques that Abel Sinkovics metaparse to parse the struct and automatically expand to the boilerplate template code for Boost.Fusion. But as this is bleeding edge and will take longer (i.e. I didn't start anything in this direction, I'm just playing a bit with metaparse and thinking how it could be done), I'm naturally open for a first iteration in this direction to see how we could change the DEFINE_STRUCT to allow adding own code to the structs from your experience. Currently I have to finish the ADAPT_ macros which are doing type deduction for declared field (actually I'm just missing the ADT_ASSOC and I'm done, but I've been alot busy last month). And if you want we can start something together Tobias to see where we will land in changing the DEFINE_STRUCT with a BEGIN and END. Would you like to work together on this ? I believe we can do something which won't break the existing DEFINE macros and allows adding own code to the defined struct.
The only problem I see is that the mechanism is private and is not guaranteed to remain unchanged.
Yes if Tobias copy/paste the code in it's project and split the macro this maybe broken by future versions of Boost.Fusion as the BOOST_FUSION_DEFINE_STRUCT_IMPL is private.
From a user point-of-view without copy pasting the whole BOOST_FUSION_DEFINE_STRUCT implementation there is no guarantee that it won't break.
Because it could be so that we add new extensions and so to the struct. This is dangerous for Tobias's code, as he wouldn't necessarily see why it's code is failing when using newer boost. We cannot give the guarantee that what the official macros do won't change. Tobias you are probably aware of this, but that means that you'll have to update your macros each time you make a boost update, or at least check they are still the same, until we get the feature upstream. :)
Actually there's work in progress cleaning up the macros and the implementation by Damien Buhl. CC'ing him now. Your thoughts, Damien?
Regards,
Cheers, -- Damien Buhl
Hi Damien, sorry for the late reply. Thanks for the offer to work on a new set of fusion-struct macros. I'd really like to be involved. The idea of using metaparse sounds interesting for parsing the options, what kind of constructors or operators to generate, but I can't see how this could help analyze the members and its names of a user defined struct like in the example you gave. (AFAIK this would require some kind of static reflection, which would involve preprocessor-programming.) Could you give some of your thoughts on how it could be done? I'll give it a try with the DEFINE_STRUCT BEGIN and END macros and post my results (though it probably will be the quite obvious result) best regards Tobias -- View this message in context: http://boost.2283326.n4.nabble.com/fusion-BOOST-FUSION-DEFINE-STRUCT-with-us... Sent from the Boost - Users mailing list archive at Nabble.com.
Which would use the same techniques that Abel Sinkovics metaparse to parse the struct and automatically expand to the boilerplate template code for Boost.Fusion.
I don't think metaparse can be used for this. It can't reference the members in the struct.
I'm naturally open for a first iteration in this direction to see how we could change the DEFINE_STRUCT to allow adding own code to the structs from your experience.
As a first iteration, it would be nice if the extension metafunctions(ie `access::struct_member`, `struct_member_name`, `struct_assoc_key`) would provide an enable parameter. This would allow the struct definitions to be inline. Boost.Fusion already provides `INLINE_STRUCT` but it doesn't provide the member name nor an associative key. When we have the members inline, we can then inherit from the base operators we would like for the class: struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (std::string, name) (int, age) ); }; And then we could have another `INLINE_CONSTRUCT` that will generate the constructor: struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE_CONSTRUCT(person, (std::string, name) (int, age) ); }; Then for those that want a define all together, we could have a macro like this: BOOST_FUSION_DEFINE(person, equality<person>, streamable<person>) ( (std::string, name) (int, age) ) So that way the user can add in the behaviours they want through inheritance. Additionally, we could also switch the type and field name order so we could handle types with commas in it: struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (name, std::string) (age, int) (locations, std::map<std::string, int>) ); }; Plus, by reversing the order we could handle the associative keys with same macro: struct person : equality<person>, streamable<person> { struct keys { struct name {}; struct age {}; struct locations {}; } BOOST_FUSION_INLINE( (name, std::string, keys::name) (age, int, keys::age) (locations, std::map<std::string, int>, keys::locations) ); }; I could add some pull requests for this, starting with the enable parameters, if there is interest in something like this. Of course, this is difference than Damien's work, which looks it was making the type optional in the adapts macros. Paul Fultz II -- View this message in context: http://boost.2283326.n4.nabble.com/fusion-BOOST-FUSION-DEFINE-STRUCT-with-us... Sent from the Boost - Users mailing list archive at Nabble.com.
On 9/12/14, 12:52 AM, pfultz2 wrote:
Which would use the same techniques that Abel Sinkovics metaparse to parse the struct and automatically expand to the boilerplate template code for Boost.Fusion.
I don't think metaparse can be used for this. It can't reference the members in the struct.
I'm naturally open for a first iteration in this direction to see how we could change the DEFINE_STRUCT to allow adding own code to the structs from your experience.
As a first iteration, it would be nice if the extension metafunctions(ie `access::struct_member`, `struct_member_name`, `struct_assoc_key`) would provide an enable parameter. This would allow the struct definitions to be inline. Boost.Fusion already provides `INLINE_STRUCT` but it doesn't provide the member name nor an associative key.
When we have the members inline, we can then inherit from the base operators we would like for the class:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (std::string, name) (int, age) ); };
And then we could have another `INLINE_CONSTRUCT` that will generate the constructor:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE_CONSTRUCT(person, (std::string, name) (int, age) ); };
Then for those that want a define all together, we could have a macro like this:
BOOST_FUSION_DEFINE(person, equality<person>, streamable<person>) ( (std::string, name) (int, age) )
So that way the user can add in the behaviours they want through inheritance.
Additionally, we could also switch the type and field name order so we could handle types with commas in it:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (name, std::string) (age, int) (locations, std::map<std::string, int>) ); };
Plus, by reversing the order we could handle the associative keys with same macro:
struct person : equality<person>, streamable<person> { struct keys { struct name {}; struct age {}; struct locations {}; } BOOST_FUSION_INLINE( (name, std::string, keys::name) (age, int, keys::age) (locations, std::map<std::string, int>, keys::locations) ); };
I could add some pull requests for this, starting with the enable parameters, if there is interest in something like this. Of course, this is difference than Damien's work, which looks it was making the type optional in the adapts macros.
I like this! Can we somehow merge this with Damien's work? Regards, -- Joel de Guzman http://www.ciere.com http://boost-spirit.com http://www.cycfi.com/
On 09/11/2014 06:52 PM, pfultz2 wrote:
Which would use the same techniques that Abel Sinkovics metaparse to parse the struct and automatically expand to the boilerplate template code for Boost.Fusion.
I don't think metaparse can be used for this. It can't reference the members in the struct.
I don't see why it couldn't, as it can parse strings at compile time and generate therefore the types needed for a struct to be adapted. We are probably referring to a different mechanism of metaparse.
I'm naturally open for a first iteration in this direction to see how we could change the DEFINE_STRUCT to allow adding own code to the structs from your experience.
As a first iteration, it would be nice if the extension metafunctions(ie `access::struct_member`, `struct_member_name`, `struct_assoc_key`) would provide an enable parameter. This would allow the struct definitions to be inline. Boost.Fusion already provides `INLINE_STRUCT` but it doesn't provide the member name nor an associative key.
When we have the members inline, we can then inherit from the base operators we would like for the class:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (std::string, name) (int, age) ); };
with BOOS_FUSION_INLINE, you mean BOOST_FUSION_DEFINE_STRUCT_INLINE no ?
And then we could have another `INLINE_CONSTRUCT` that will generate the constructor:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE_CONSTRUCT(person, (std::string, name) (int, age) ); };
Then for those that want a define all together, we could have a macro like this:
BOOST_FUSION_DEFINE(person, equality<person>, streamable<person>) ( (std::string, name) (int, age) )
So that way the user can add in the behaviours they want through inheritance.
Additionally, we could also switch the type and field name order so we could handle types with commas in it:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (name, std::string) (age, int) (locations, std::map<std::string, int>) ); };
Plus, by reversing the order we could handle the associative keys with same macro:
struct person : equality<person>, streamable<person> { struct keys { struct name {}; struct age {}; struct locations {}; } BOOST_FUSION_INLINE( (name, std::string, keys::name) (age, int, keys::age) (locations, std::map<std::string, int>, keys::locations) ); };
I could add some pull requests for this, starting with the enable parameters, if there is interest in something like this. Of course, this is difference than Damien's work, which looks it was making the type optional in the adapts macros.
This is naturally different, as we have two different use-cases : 1. existing structs that we want to adapt (we don't want to repeat the type there) 2. Directly defining structs (we want to declare the type) as boost fusion enabled types. What I'm doing is for the use case 1. and this only touch ADAPT_STRUCT macros, what you are proposing is for the 2nd use case which extends DEFINE_STRUCT macros. So concurrent work won't collide, eventually we can do this in the same repository ? I can give you access to mine or we can open up a mini-organization on github (e.g. boost-fusion-staging) to handle this work, so that we can then make a clean pull-request to the official repo. @Tobias Loew would it also solve your problems? Or do you still think modifying BOOST_FUSION_DEFINE_STRUCT would be better ? Could we work all three together on this? We just have to cleanly define who does what to avoid being slowed down by each other (all doing the same differently). I'm soon finished with the ADAPT_* macros, so I'll be able to focus on this.
Paul Fultz II
-- View this message in context: http://boost.2283326.n4.nabble.com/fusion-BOOST-FUSION-DEFINE-STRUCT-with-us... Sent from the Boost - Users mailing list archive at Nabble.com. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
I don't think metaparse can be used for this. It can't reference the
members
in the struct.
I don't see why it couldn't, as it can parse strings at compile time and generate therefore the types needed for a struct to be adapted. We are probably referring to a different mechanism of metaparse.
Yes you can parse a string and have it generate a template type, but you can't create a template that accesses a member by a name that is in the string. That is templates can't map a string to a symbol names. For example, say you want to access members as single letters: struct point { int x; int y; }; point p{}; access<'x'>::get(p) = 5; // Set the 'x' member field to 5 Now you can't write this access class: template<char MemberName> struct access { template<class T> static auto& get(T& x) { return x.MemberName; // This isn't possible } }; Of course, you could specialize the template for every possible `char` input, but that just isn't feasible. The only way is to use the preprocessor.
As a first iteration, it would be nice if the extension metafunctions(ie `access::struct_member`, `struct_member_name`, `struct_assoc_key`) would provide an enable parameter. This would allow the struct definitions to be inline. Boost.Fusion already provides `INLINE_STRUCT` but it doesn't provide the member name nor an associative key.
When we have the members inline, we can then inherit from the base operators we would like for the class:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (std::string, name) (int, age) ); };
with BOOS_FUSION_INLINE, you mean BOOST_FUSION_DEFINE_STRUCT_INLINE no ?
Well, thats what im referring to. However, we may want to have a different name for two reasons: 1) If we switch the order of the variable and type so it can handle types with commas in them, this will break backwards compatibility. 2) There is a lot of work that has been done to get the current `BOOST_FUSION_DEFINE_STRUCT_INLINE` to work on older compilers. Changing the implenetation could affect that, and I dont really have access to some of those older compilers.
This is naturally different, as we have two different use-cases :
1. existing structs that we want to adapt (we don't want to repeat the type there) 2. Directly defining structs (we want to declare the type) as boost fusion enabled types.
What I'm doing is for the use case 1. and this only touch ADAPT_STRUCT macros, what you are proposing is for the 2nd use case which extends DEFINE_STRUCT macros.
So concurrent work won't collide, eventually we can do this in the same repository ? I can give you access to mine or we can open up a mini-organization on github (e.g. boost-fusion-staging) to handle this work, so that we can then make a clean pull-request to the official repo.
@Tobias Loew would it also solve your problems? Or do you still think modifying BOOST_FUSION_DEFINE_STRUCT would be better ?
Could we work all three together on this? We just have to cleanly define who does what to avoid being slowed down by each other (all doing the same differently). I'm soon finished with the ADAPT_* macros, so I'll be able to focus on this.
Yes, we shouldn't collide. I can start something in my repo, and either open a pull request to your repo, or I could directly to Boost.Fusion and you and Joel can take a look at it. I'll try to come up with something this week. Paul Fultz II -- View this message in context: http://boost.2283326.n4.nabble.com/fusion-BOOST-FUSION-DEFINE-STRUCT-with-us... Sent from the Boost - Users mailing list archive at Nabble.com.
On 09/15/2014 06:03 AM, pfultz2 wrote:
I don't think metaparse can be used for this. It can't reference the
members
in the struct.
I don't see why it couldn't, as it can parse strings at compile time and generate therefore the types needed for a struct to be adapted. We are probably referring to a different mechanism of metaparse.
Yes you can parse a string and have it generate a template type, but you can't create a template that accesses a member by a name that is in the string. That is templates can't map a string to a symbol names. For example, say you want to access members as single letters:
struct point { int x; int y; };
point p{}; access<'x'>::get(p) = 5; // Set the 'x' member field to 5
Now you can't write this access class:
template<char MemberName> struct access { template<class T> static auto& get(T& x) { return x.MemberName; // This isn't possible } };
Of course, you could specialize the template for every possible `char` input, but that just isn't feasible. The only way is to use the preprocessor.
I wasn't referring to access classes, in fact I want to implement a C++ declaration parser that would expand to the templates instantiation needed by Boost.Fusion. This is crazy and would take ages to compile, but with a subset of metaparse specific for the job it could be usable on modern compilers.
As a first iteration, it would be nice if the extension metafunctions(ie `access::struct_member`, `struct_member_name`, `struct_assoc_key`) would provide an enable parameter. This would allow the struct definitions to be inline. Boost.Fusion already provides `INLINE_STRUCT` but it doesn't provide the member name nor an associative key.
When we have the members inline, we can then inherit from the base operators we would like for the class:
struct person : equality<person>, streamable<person> { BOOST_FUSION_INLINE( (std::string, name) (int, age) ); };
with BOOS_FUSION_INLINE, you mean BOOST_FUSION_DEFINE_STRUCT_INLINE no ?
Well, thats what im referring to. However, we may want to have a different name for two reasons:
1) If we switch the order of the variable and type so it can handle types with commas in them, this will break backwards compatibility.
2) There is a lot of work that has been done to get the current `BOOST_FUSION_DEFINE_STRUCT_INLINE` to work on older compilers. Changing the implenetation could affect that, and I dont really have access to some of those older compilers.
This may however be better for maintenance of all the code, but start it aside, and we can see how we can merge this then it works for one compiler. I'm currently setting up a farm of virtual appliances to test all those compilers, especially to test my patch for the ADAPT_STRUCT. I'll give you access too, to the buildbots.
This is naturally different, as we have two different use-cases :
1. existing structs that we want to adapt (we don't want to repeat the type there) 2. Directly defining structs (we want to declare the type) as boost fusion enabled types.
What I'm doing is for the use case 1. and this only touch ADAPT_STRUCT macros, what you are proposing is for the 2nd use case which extends DEFINE_STRUCT macros.
So concurrent work won't collide, eventually we can do this in the same repository ? I can give you access to mine or we can open up a mini-organization on github (e.g. boost-fusion-staging) to handle this work, so that we can then make a clean pull-request to the official repo.
@Tobias Loew would it also solve your problems? Or do you still think modifying BOOST_FUSION_DEFINE_STRUCT would be better ?
Could we work all three together on this? We just have to cleanly define who does what to avoid being slowed down by each other (all doing the same differently). I'm soon finished with the ADAPT_* macros, so I'll be able to focus on this.
Yes, we shouldn't collide. I can start something in my repo, and either open a pull request to your repo, or I could directly to Boost.Fusion and you and Joel can take a look at it. I'll try to come up with something this week.
Paul Fultz II
Then to avoid slowing you down, do it directly to the repository of boostorg/fusion when you'll be finished, don't stress that's open source ;). I'll follow your repo and watch all pull-requests to boostorg/fusion so I would comment there too, where are you on github ? Don't hesitate to ask for what you would need me when you'll be deeper in your draft, possibly is Tobias Loew also interested and would also want to know how to help. Cheers, -- Damien Buhl
participants (4)
-
Damien Buhl
-
Joel de Guzman
-
pfultz2
-
Tobias Loew