BoostFusion is arranged so that the user can extend it to provide their own objects which can be indexed either sequentially or by keyword. An example of this is given in the documentation. What follows is some of the code for this. The full code can be found in the BoostLibraries distribution. This is one way to build CppHeterogeneousContainers. -- JohnFletcher
I worked on this some years ago and then set it aside. I have now picked this up again and using the variadic template features of CeePlusPlusEleven it is possible to make a BoostFusionVariadicUserExtension which is much easier to use as the many files in the detail section become general and all the user has to do is define the structure and the keys. -- JohnFletcher
namespace example { struct example_struct { std::string name; int age; example_struct(const std::string& n,int a) : name(n), age(a) {} }; }This can be accessed as follows:
int main() { example::example_struct bert("bert", 99); using namespace boost::fusion; BOOST_MPL_ASSERT((traits::is_associative<example::example_struct>)); BOOST_MPL_ASSERT((traits::is_random_access<example::example_struct>)); BOOST_MPL_ASSERT((traits::is_sequence<example::example_struct>)); BOOST_TEST(deref(begin(bert)) == "bert"); BOOST_TEST(*next(begin(bert)) == 99); BOOST_TEST(*prior(end(bert)) == 99); BOOST_TEST(*advance_c<1>(begin(bert)) == 99); BOOST_TEST(*advance_c<-1>(end(bert)) == 99); BOOST_TEST(distance(begin(bert), end(bert)) == 2); typedef result_of::begin<example::example_struct>::type first; typedef result_of::next<first>::type second; BOOST_MPL_ASSERT((boost::is_same<result_of::value_of<first>::type, std::string>)); BOOST_MPL_ASSERT((boost::is_same<result_of::value_of<second>::type, int>)); BOOST_TEST(begin(bert) != end(bert)); BOOST_TEST(advance_c<2>(begin(bert)) == end(const_cast<const example::example_struct&>(bert))); BOOST_TEST(at_c<0>(bert) == "bert"); BOOST_TEST(at_c<1>(bert) == 99); BOOST_TEST(at_key<fields::name>(bert) == "bert"); BOOST_TEST(at_key<fields::age>(bert) == 99); BOOST_TEST(has_key<fields::name>(bert)); BOOST_TEST(has_key<fields::age>(bert)); BOOST_TEST(!has_key<int>(bert)); BOOST_MPL_ASSERT((boost::is_same<result_of::value_at_c<example::example_struct, 0>::type, std::string>)); BOOST_MPL_ASSERT((boost::is_same<result_of::value_at_c<example::example_struct, 1>::type, int>)); BOOST_MPL_ASSERT((boost::is_same<result_of::value_at_key<example::example_struct, fields::name>::type, std::string>)); BOOST_MPL_ASSERT((boost::is_same<result_of::value_at_key<example::example_struct, fields::age>::type, int>)); BOOST_TEST(size(bert) == 2); return boost::report_errors(); }There is a set of tags set up as follows.
namespace example { struct example_sequence_tag; } namespace boost { namespace fusion { namespace traits { template<> struct tag_of<example::example_struct> { typedef example::example_sequence_tag type; }; }}}The tags are defined like this:
namespace fields { struct name; struct age; } namespace example { struct example_sequence_tag; } namespace boost { namespace fusion { namespace extension { template<typename Tag> struct at_key_impl; template<> struct at_key_impl<example::example_sequence_tag> { template<typename Sequence, typename Key> struct apply; template<typename Sequence> struct apply<Sequence, fields::name> { typedef typename mpl::if_< is_const<Sequence>, std::string const&, std::string&>::type type; static type call(Sequence& seq) { return seq.name; }; }; template<typename Sequence> struct apply<Sequence, fields::age> { typedef typename mpl::if_< is_const<Sequence>, int const&, int&>::type type; static type call(Sequence& seq) { return seq.age; }; }; }; } }}
CategoryBoost CategoryCpp CategoryCppTemplates CategoryContainer