BOOST_FUSION_ADAPT_STRUCT limits

I tried playing with the BOOST_FUSION_ADAPT_STRUCT macro and tried some naive things, such as using Fusion to print any arbitrary structure.

Starting with this sample code provided in the documentation , I was not able to perform some operations on my adapted structure that were allowed using the merge sequence,

 #include <boost/fusion/adapted.hpp> #include <boost/fusion/sequence/io/out.hpp> #include <boost/fusion/sequence/intrinsic.hpp> #include <boost/fusion/view.hpp> #include <iostream> namespace fuz = boost::fusion; namespace demo { struct employee { std::string name; int age; }; } // demo::employee is now a Fusion sequence BOOST_FUSION_ADAPT_STRUCT( demo::employee, (std::string, name) (int, age)) int main() { // tried to initialize an employee like a fusion sequence // but it didnt work // demo::employee e("bob", 42); demo::employee e; e.name = "bob"; e.age = 42; // Access struct members with fusion random access functions // ok std::cout << fuz::at_c<0>(e) << std::endl; // tried to print the struct like any othe fusion sequence // didnt work // std::cout << e << std::endl; // I made it work by using a fusion view // is it the right way? std::cout << fuz::as_nview<0, 1>(e) << std::endl; } 

This leads me to the following questions:

  • Why is Fusion magik not working here?

  • Is using a view the right way to print an adapted structure?

  • How far can an adapted structure be used as a Fusion sequence?

+7
c ++ metaprogramming boost-fusion
source share
2 answers

From the documentation of boost::fusion :

I / O statements overloaded in boost :: fusion namespace

This means that if you need an implicit integration of these operator<< , you need to enter the boost::fusion namespace in the current namespace ( :: here) or use them explicitly.

To summarize, add:

 using namespace boost::fusion; 

Should work in your case. Or for explicit use, you will need to write:

 boost::fusion::operator<<(std::cout, e) << std::endl; 

--- EDIT ---

After a little reading of the boost::fusion code, it seems like you got confused by looking for Koenig boost::fusion::operators::operator<< , which is selected if your argument is real boost::fusion::sequence .

This is why you do not need to enter the boost::fusion namespace or explicitly call boost::fusion::operator<< for the types defined in the boost::fusion namespace.

Some explanations:

I will not explain the whole Koenig search concept (also known as Dependent Lookup - ADL) here since it is not, but basically, it claims that if you use a variable whose type is inside the namespace, then the function search extends to the space names of this parameter.

In this particular case, including boost/fusion/sequence/io/out.hpp , boost::fusion::operator::operator<< will be defined, which will then be entered into the boost::fusion namespace.

 $ cat /usr/local/include/boost/fusion/sequence/io/out.hpp [...] namespace boost { namespace fusion { [...] namespace operators { template <typename Sequence> inline typename boost::enable_if< fusion::traits::is_sequence<Sequence> , std::ostream& >::type // this is just a SFINAE trick to ensure // the function will only be selected for // actual boost::fusion::sequence operator<<(std::ostream& os, Sequence const& seq) { return fusion::out(os, seq); // this will print out the sequence } } using operators::operator<<; // here the operator<< is injected // in boost::fusion }} 

This means that calls using operator<< with parameters whose types are in the boost::fusion namespace will find the necessary overload.

Calls using arguments whose type is not in this namespace will not be able to allow proper operator<< overloading (this is in your example).

You can verify this by specifying your type in the boost::fusion namespace.

 namespace boost { namespace fusion { struct employee { std::string name; int age; }; }} BOOST_FUSION_ADAPT_STRUCT( boost::fusion::employee, (std::string, name) (int, age)) [...] boost::fusion::employee e; std::cout << e << std::endl; // ADL will work here 

Note: if you want to debug such name lookup problems, you must use gdb . This way you will always know which overload has been selected. In this case:

 $ cat fusion.cpp #include <iostream> #include <cstdlib> #include <boost/fusion/container/vector.hpp> #include <boost/fusion/sequence/io.hpp> int main(int, char**) { boost::fusion::vector<int, char> foo(42, '?'); std::cout << foo << std::endl; return EXIT_SUCCESS; } $ gdb -q ./fusion Reading symbols for shared libraries ... done (gdb) b 10 Breakpoint 1 at 0x1000012f7: file fusion.cpp, line 10. (gdb) r Starting program: /Users/avallee/Projects/tmp/fusion Reading symbols for shared libraries ++............................. done Breakpoint 1, main (unnamed_arg=0x7fff5fbffb60, unnamed_arg=0x7fff5fbffb60) at fusion.cpp:10 10 std::cout << foo << std::endl; (gdb) s boost::fusion::operators::operator<< <boost::fusion::vector<int, char, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > ( os=@0x7fff762b5f10 , seq=@0x7fff5fbffb18 ) at out.hpp:38 38 return fusion::out(os, seq); 
+8
source share

Many thanks to Aurelien for the detailed explanation. I also found this post in google groups. As your explanation leads to the fact that the easiest way to get the job done is to put this in the demo namespace:

 namespace demo{ using boost::fusion::operators::operator<<; ... 
+4
source share

All Articles