Question

I'd like to iterate through the member of any fusion struct, add its member's type to a boost::mpl::vector (or set) to create a boost::variant of those types. Any help is appreciated.

struct A
{
    int a1;
    double a2;
    float a3;
};

BOOST_FUSION_ADAPT_STRUCT(
    A,
    (int,a1)
    (double,a2)
    (float,a3)
)

struct StructTypes
{
    template <typename T>
    void operator()( T& t ) const 
    {
        // how do I append to a list of types here?
    }
};

int main()
{
    A a;
    boost::fusion::for_each( a, StructTypes() );
}
Was it helpful?

Solution

I'm no expert, but I think you can't accomplish what you want using fusion::for_each. One very easy alternative that can work is using fusion::joint_view to concatenate the mpl::vector with your struct (the sequence your struct is adapted to). This joint view can't be used directly in boost::make_variant_over, but this can be easily solved by using fusion::result_of::as_vector to get a fusion::vector with the same elements. One problem with this approach (I'm not sure it is really a problem, but it is undoubtedly ugly) is that if you have elements in common between your vector and your struct, the resulting variant will have those elements twice in its list of types. If you want to solve this you can use an mpl::set instead of your vector and then use mpl::fold<A, mpl::set<your types...>, mpl::insert<_1,_2> >::type. This gives you a mpl::set without any duplicated types. You'll need to use fusion::result_of::as_vector again in order to use make_variant_over.

Running on Coliru

#include <iostream>
#include <string>

#include <boost/variant.hpp>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/mpl.hpp> //important: allows compatibility fusion-mpl
#include <boost/fusion/include/joint_view.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/set.hpp>
#include <boost/fusion/include/fold.hpp>
#include <boost/fusion/include/for_each.hpp>


#include <boost/mpl/fold.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/insert.hpp>

namespace fusion=boost::fusion;
namespace mpl=boost::mpl;

struct A
{
    int a1;
    double a2;
    float a3;
};

BOOST_FUSION_ADAPT_STRUCT(
    A,
    (int,a1)
    (double,a2)
    (float,a3)
)

struct printer
{
    template <typename T>
    void operator()(T) const
    {
        std::cout << typeid(T).name() << ";";
    }
};


int main()
{
    typedef fusion::result_of::as_vector<fusion::joint_view<mpl::vector<bool,std::string>,A> >::type  types1;
    typedef boost::make_variant_over<types1>::type variant1;

    variant1 a = 3.5f;
    variant1 b = true;

    std::cout << a << " " << b << ". " << fusion::result_of::size<variant1::types>::type::value << " elements in the variant" << std::endl;
    fusion::for_each(variant1::types(),printer());
    std::cout << std::endl;

    typedef mpl::fold<A,mpl::set<std::string,int>,mpl::insert<mpl::_1,mpl::_2>>::type types2;
    typedef boost::make_variant_over<fusion::result_of::as_vector<types2>::type>::type variant2;

    variant2 a2 = 4;
    variant2 b2 = "bla"; 

    std::cout << a2 << " " << b2 << ". " << fusion::result_of::size<variant2::types>::type::value << " elements in the variant" << std::endl;
    fusion::for_each(variant2::types(),printer());
    std::cout << std::endl;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top