Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
----- Original Message ----- From: "Hicham Mouline" <hicham@mouline.org> To: <boost-users@lists.boost.org> Sent: Tuesday, January 19, 2010 4:22 PM Subject: Re: [Boost-users] fusion struct adapt macro,construct the struct from a fusion vector
What about:
template <typename Seq> params(Seq const& seq, typename boost::enable_if< fusion::traits::is_sequence<Seq>
::type* = NULL);
?
Fantastic.
Here is the code I have (plz see below), but it seems there are issues with const-ness that I don't understand.
Following my previous attempt, replacing the functor applied by foreach to the zipped sequence by: struct assignelt { template <typename T> void operator()( const vector2<const T&, const T&>& seqpairs ) const { typedef vector2<const T&, const T&> pair_t; const_cast<T&>(at_c<0, const pair_t>(seqpairs)) = at_c<1, const pair_t>(seqpairs); } }; works. I can now construct my struct params from an equivalent fusion sequence. This constructor is identical for all my params struct. I have structs params1 to params100 Is there a way to factorise this ctor and not repeat its definition in the 100 struct params? Is this possible with a base struct templated on the derived struct? rds,
On 1/20/2010 2:05 AM, Hicham Mouline wrote:
Following my previous attempt, replacing the functor applied by foreach to the zipped sequence by:
struct assignelt {
template <typename T> void operator()( const vector2<const T&, const T&>& seqpairs ) const { typedef vector2<const T&, const T&> pair_t; const_cast<T&>(at_c<0, const pair_t>(seqpairs)) = at_c<1, const pair_t>(seqpairs); } }; works.
I can now construct my struct params from an equivalent fusion sequence. This constructor is identical for all my params struct. I have structs params1 to params100
Is there a way to factorise this ctor and not repeat its definition in the 100 struct params? Is this possible with a base struct templated on the derived struct?
Wow. 100! Anyway, I've seem to lost context already. Pardon me, I'm not following this thread well. Could you rephrase the problem again in simpler terms? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net http://www.facebook.com/djowel Meet me at BoostCon http://www.boostcon.com/home http://www.facebook.com/boostcon
----- Original Message ----- From: "Joel de Guzman" <joel@boost-consulting.com> To: <boost-users@lists.boost.org> Sent: Wednesday, January 20, 2010 9:48 AM Subject: Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
On 1/20/2010 2:05 AM, Hicham Mouline wrote:
Following my previous attempt, replacing the functor applied by foreach to the zipped sequence by:
struct assignelt {
template <typename T> void operator()( const vector2<const T&, const T&>& seqpairs ) const { typedef vector2<const T&, const T&> pair_t; const_cast<T&>(at_c<0, const pair_t>(seqpairs)) = at_c<1, const pair_t>(seqpairs); } }; works.
I can now construct my struct params from an equivalent fusion sequence. This constructor is identical for all my params struct. I have structs params1 to params100
Is there a way to factorise this ctor and not repeat its definition in the 100 struct params? Is this possible with a base struct templated on the derived struct?
Wow. 100! Anyway, I've seem to lost context already. Pardon me, I'm not following this thread well. Could you rephrase the problem again in simpler terms?
Regards, Yes, something in that order. We are testing systems and we don't know which will give the best results.
With your and Hartmut's help, I wrote a constructor for my struct pararms that takes a fusion sequence as an argument: template<typename Seq> params( const Seq& seq, ... ) { for_each( zip(*this, seq), assignelt() ); } params is adapted to be a fusion sequence. assignelt() is the functor that assigns from seq to params with the help of the zipped sequence Now, my question was whether the ctor could be refactored because it is identical for all the 100 params structs. Regards,
On 1/20/2010 11:43 AM, Hicham Mouline wrote:
Yes, something in that order. We are testing systems and we don't know which will give the best results.
With your and Hartmut's help, I wrote a constructor for my struct pararms that takes a fusion sequence as an argument:
template<typename Seq> params( const Seq& seq, ... ) { for_each( zip(*this, seq), assignelt() ); }
params is adapted to be a fusion sequence. assignelt() is the functor that assigns from seq to params with the help of the zipped sequence
Now, my question was whether the ctor could be refactored because it is identical for all the 100 params structs.
So you have 100 similar structs that all want to to have this constructor? But why? Why not simply work on fusion::vectors instead of adapting structs? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net http://www.facebook.com/djowel Meet me at BoostCon http://www.boostcon.com/home http://www.facebook.com/boostcon
----- Original Message ----- From: "Joel de Guzman" <joel@boost-consulting.com> To: <boost-users@lists.boost.org> Sent: Wednesday, January 20, 2010 10:55 AM Subject: Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
On 1/20/2010 11:43 AM, Hicham Mouline wrote:
Yes, something in that order. We are testing systems and we don't know which will give the best results.
With your and Hartmut's help, I wrote a constructor for my struct pararms that takes a fusion sequence as an argument:
template<typename Seq> params( const Seq& seq, ... ) { for_each( zip(*this, seq), assignelt() ); }
params is adapted to be a fusion sequence. assignelt() is the functor that assigns from seq to params with the help of the zipped sequence
Now, my question was whether the ctor could be refactored because it is identical for all the 100 params structs.
So you have 100 similar structs that all want to to have this constructor? But why? Why not simply work on fusion::vectors instead of adapting structs?
Regards,
Because I wish to leave the machinery of fusion and spirit not very visible to the user. The user only works with the structs, aggregates of parameters. Parsing into those structs from input streams is what drove me to use those spirit and fusion. Ideally, the user would define the struct, and hop, I would generate the parser for them at compile time(the questions for this are in spirit users mailing list), fill up the struct for them at runtime (I do the parsing for them), then in the rest of their code, they would use just the struct directly. But maybe I am going about this in a wrong way? The user's direct is defined in a header file, some translation units would deal just with the struct raw. Other translation units would deal with the fusion/spirit parsing machinery. Maybe some adapt macro a la FUSION_ADAPT could add the ctor and its definition, or something like deriving from a common base class? I'd love to explain more fully my application but I find it hard to do with an email and easier in an realtime medium... rds,
On 1/20/2010 6:31 PM, Hicham Mouline wrote:
----- Original Message ----- From: "Joel de Guzman" <joel@boost-consulting.com> To: <boost-users@lists.boost.org> Sent: Wednesday, January 20, 2010 10:55 AM Subject: Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
On 1/20/2010 11:43 AM, Hicham Mouline wrote:
Yes, something in that order. We are testing systems and we don't know which will give the best results.
With your and Hartmut's help, I wrote a constructor for my struct pararms that takes a fusion sequence as an argument:
template<typename Seq> params( const Seq& seq, ... ) { for_each( zip(*this, seq), assignelt() ); }
params is adapted to be a fusion sequence. assignelt() is the functor that assigns from seq to params with the help of the zipped sequence
Now, my question was whether the ctor could be refactored because it is identical for all the 100 params structs.
So you have 100 similar structs that all want to to have this constructor? But why? Why not simply work on fusion::vectors instead of adapting structs?
Regards,
Because I wish to leave the machinery of fusion and spirit not very visible to the user. The user only works with the structs, aggregates of parameters. Parsing into those structs from input streams is what drove me to use those spirit and fusion.
Ideally, the user would define the struct, and hop, I would generate the parser for them at compile time(the questions for this are in spirit users mailing list), fill up the struct for them at runtime (I do the parsing for them), then in the rest of their code, they would use just the struct directly.
But maybe I am going about this in a wrong way?
The user's direct is defined in a header file, some translation units would deal just with the struct raw. Other translation units would deal with the fusion/spirit parsing machinery. Maybe some adapt macro a la FUSION_ADAPT could add the ctor and its definition, or something like deriving from a common base class?
I'd love to explain more fully my application but I find it hard to do with an email and easier in an realtime medium...
Ok, understood. Well, then I suggest that you don't mess with the structs and leave them alone. The goal of FUSION_ADAPT is non-intrusive adaptation. Instead, if you control the assignment to your structs from fusion vectors anyway (which I imagine is the case because as you said, your users do not have to deal with fusion vectors), then I suggest a generic free function assign instead of decorating all your structs: template<typename Struct, typename Seq> void assign( Struct& v, const Seq& seq ) { ... } Or, if you can wait a bit, I do intend to write an intrusive version of the FUSION_ADAPT_STRUCT which also generates the struct along with the constructors and assignment to/from fusion sequences. I dunno, perhaps you can persuade a fusion guru to write the code (Christopher)? :-) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net http://www.facebook.com/djowel Meet me at BoostCon http://www.boostcon.com/home http://www.facebook.com/boostcon
Joel de Guzman wrote:
Or, if you can wait a bit, I do intend to write an intrusive version of the FUSION_ADAPT_STRUCT which also generates the struct along with the constructors and assignment to/from fusion sequences. I dunno, perhaps you can persuade a fusion guru to write the code (Christopher)? :-)
This isn't all of the above, but the attached worked for me as of Boost 1.35.0... #include <boost/fusion/adapted/struct/adapt_struct.hpp> #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/preprocessor/seq/enum.hpp> #include <boost/preprocessor/seq/transform.hpp> // only for testing #include <iostream> // BOOST_FUSION_BUILD_STRUCT() borrows its syntax from // BOOST_FUSION_ADAPT_STRUCT(). The general idea is that you write the same // code you'd have written for BOOST_FUSION_ADAPT_STRUCT(), but the _BUILD_ // variant actually declares the struct for you as well. The trouble with // BOOST_FUSION_ADAPT_STRUCT's member syntax is that it's a PP sequence of // tuples. BOOST_PP_SEQ_FOR_EACH() handles sequences of single tokens fine, // but a sequence of tuples breaks it. An implementation based on // BOOST_PP_SEQ_FOR_EACH() would require double parentheses, e.g.: // BOOST_FUSION_BUILD_STRUCT(employee, ((std::string, name))((int, age))) // But clearly BOOST_FUSION_ADAPT_STRUCT() manages to avoid that, so we borrow // its implementation. Thanks to Paul Mensonides and Joel de Guzman! #define BOOST_FUSION_BUILD_STRUCT(name, bseq) \ BOOST_FUSION_BUILD_STRUCT_I( \ name, BOOST_PP_CAT(BOOST_FUSION_BUILD_STRUCT_X bseq, 0)); \ BOOST_FUSION_ADAPT_STRUCT(name, bseq) \ /***/ #define BOOST_FUSION_BUILD_STRUCT_X(x, y) ((x, y)) BOOST_FUSION_BUILD_STRUCT_Y #define BOOST_FUSION_BUILD_STRUCT_Y(x, y) ((x, y)) BOOST_FUSION_BUILD_STRUCT_X #define BOOST_FUSION_BUILD_STRUCT_X0 #define BOOST_FUSION_BUILD_STRUCT_Y0 // BOOST_FUSION_BUILD_STRUCT_I generates the overarching structure and uses // SEQ_FOR_EACH_I to generate the "linear" substructures. // Thanks to Paul Mensonides for the PP macro help. #define BOOST_FUSION_BUILD_STRUCT_I(name, seq) \ struct name \ { \ name(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(BOOST_FUSION_BUILD_STRUCT_P, ~, seq))): \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(BOOST_FUSION_BUILD_STRUCT_MI, ~, seq)) \ {} \ BOOST_PP_SEQ_FOR_EACH_I(BOOST_FUSION_BUILD_STRUCT_C, ~, seq) \ } \ /***/ #define BOOST_FUSION_BUILD_STRUCT_P(r, ignore, xy) \ BOOST_PP_TUPLE_ELEM(2, 0, xy) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, xy), _) \ /***/ #define BOOST_FUSION_BUILD_STRUCT_MI(r, ignore, xy) \ BOOST_PP_TUPLE_ELEM(2, 1, xy)(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, xy), _)) \ /***/ #define BOOST_FUSION_BUILD_STRUCT_C(r, ignore, i, xy) \ BOOST_PP_TUPLE_ELEM(2, 0, xy) BOOST_PP_TUPLE_ELEM(2, 1, xy); \ /***/ // Example BOOST_FUSION_BUILD_STRUCT(employee, (std::string, name) (int, age)) int main(int argc, char *argv[]) { employee Jane("Jane", 37); std::cout << "Name " << Jane.name << ", age " << Jane.age << '\n'; return 0; }
On 1/21/2010 5:24 AM, Nat Goodspeed wrote:
Joel de Guzman wrote:
Or, if you can wait a bit, I do intend to write an intrusive version of the FUSION_ADAPT_STRUCT which also generates the struct along with the constructors and assignment to/from fusion sequences. I dunno, perhaps you can persuade a fusion guru to write the code (Christopher)? :-)
This isn't all of the above, but the attached worked for me as of Boost 1.35.0...
Aha! Someone took the challenge :-) I should post more challenges like this. There are lots of bits and pieces that I'd appreciate help on. This is one of 'em. Anyway... my hesitation is that the struct is placed in global namespace. Is it still usable when the macro invoked in a specific namespace? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net http://www.facebook.com/djowel Meet me at BoostCon http://www.boostcon.com/home http://www.facebook.com/boostcon
----- Original Message ----- From: "Joel de Guzman" <joel@boost-consulting.com> To: <boost-users@lists.boost.org> Sent: Wednesday, January 20, 2010 6:09 PM Subject: Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
Ok, understood. Well, then I suggest that you don't mess with the structs and leave them alone. The goal of FUSION_ADAPT is non-intrusive adaptation. Instead, if you control the assignment to your structs from fusion vectors anyway (which I imagine is the case because as you said, your users do not have to deal with fusion vectors), then I suggest a generic free function assign instead of decorating all your structs:
template<typename Struct, typename Seq> void assign( Struct& v, const Seq& seq ) { ... } The free function is what I went with and it works perfectly fine with my different params structs. Thanks,
participants (3)
-
Hicham Mouline
-
Joel de Guzman
-
Nat Goodspeed