[MPL] Generating multi-index container indices based on MPL tag dispatching

Hi all, this is a follow-up of my question of yesterday (Fold a vector of pairs). The example here is a lot more elaborate and more like the final code I'd like to achieve. I still get errors when compiling the code below related the use of mpl::second<mpl::_2>. I'm trying to generate a multi-index container type that will store objects generated using inherit_linearly. The objects contain a number of attributes (all int in this example) based on a typelist of attribute tags. I want to generate this container by providing the object type and a index_list as shown here: http://www.boost.org/doc/libs/1_49_0/libs/multi_index/doc/tutorial/technique... I'm trying to compose the index_list using some kind of MPL tag dispatch based on the unique & non_unique tags to generate unique & non_unique ordered indices for the container. It's clear to me that the errors have to do with the MPL placeholder expressions used in the 3 types passed to the multi_index::member template class. This is confirmed because if I replace these 3 template parameters by the ones which are comment out just below the program compiles fine. From my previous question I get that the placeholder expressions need to be evaluated lazily (so no ::type or ::value - obviously the code below is thus incorrect). I've been reading section 3.3 of the MPL book on 'Handling Placeholders' a couple of times and from this it seems I need 3 metafunctions that call apply<> on the passed placeholder expressions and which would return each of the types to be passed to multi_index::member<>? I've been trying different approaches but none have been successful... I'm still not grasping how to handle these placeholder expressions... I hope the great minds on this list can bring some light in my clouded mind... Thanks & kind regards, Peter //------------------------------------------------- #include <boost/mpl/at.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/inherit_linearly.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/fold.hpp> #include <boost/mpl/pair.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/vector.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/indexed_by.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> namespace mpl = boost::mpl; namespace bmi = boost::multi_index; enum attributeTags { ATTR_1, ATTR_2, ATTR_3 }; template <int attrId> struct AttrTraits { typedef int type; }; template <typename AttrT> struct Attribute { typedef AttrTraits<AttrT::value> ATraits; typename ATraits::type value; }; template <typename AttrList> struct Object : public boost::mpl::inherit_linearly< AttrList, boost::mpl::inherit<boost::mpl::_1, Attribute<boost::mpl::_2> >
::type {};
struct unique {}; struct non_unique {}; template <typename T> struct is_unique : boost::false_type {}; template <> struct is_unique<unique> : boost::true_type {}; template<typename ObjectT, typename IndicesMap> struct ObjectContainer { typedef typename mpl::fold< IndicesMap, mpl::vector<>, mpl::if_< is_unique<mpl::first<mpl::_2> >, mpl::push_back< mpl::_1, bmi::ordered_unique< bmi::member< Attribute<boost::mpl::second<boost::mpl::_2> >, AttrTraits<boost::mpl::second<boost::mpl::_2>::value>::type, &Attribute<boost::mpl::second<boost::mpl::_2> >::value // Attribute<boost::mpl::int_<0> >, // int, // &Attribute<boost::mpl::int_<0> >::value
,
mpl::push_back< mpl::_1, bmi::ordered_non_unique< bmi::member< Attribute<boost::mpl::second<boost::mpl::_2> >, AttrTraits<boost::mpl::second<boost::mpl::_2>::value>::type, &Attribute<boost::mpl::second<boost::mpl::_2> >::value // Attribute<boost::mpl::int_<1> >, // int, // &Attribute<boost::mpl::int_<1> >::value
::type IndexList;
typedef boost::multi_index_container<ObjectT, IndexList> Container_t; Container_t Container; }; int main() { typedef boost::mpl::vector< boost::mpl::int_<ATTR_1>, boost::mpl::int_<ATTR_2>, boost::mpl::int_<ATTR_3>
AttributeList_1;
typedef Object<AttributeList_1> Object_1; typedef mpl::vector< mpl::pair<unique, mpl::int_<ATTR_1> >, mpl::pair<non_unique, mpl::int_<ATTR_2> >
Object_1_Indicex;
ObjectContainer<Object_1, Object_1_Indicex> Object1Container; return 0; } //-------------------------------------------------

On Thu, Mar 15, 2012 at 3:29 AM, Peter Nyssen <peter@dynsws.com> wrote:
Hi all,
this is a follow-up of my question of yesterday (Fold a vector of pairs). The example here is a lot more elaborate and more like the final code I'd like to achieve. I still get errors when compiling the code below related the use of mpl::second<mpl::_2>.
[...] (My response is independent of your provided context.)
From my previous question I get that the placeholder expressions need to be evaluated lazily (so no ::type or ::value - obviously the code below is thus incorrect). I've been reading section 3.3 of the MPL book on 'Handling Placeholders' a couple of times and from this it seems I need 3 metafunctions that call apply<> on the passed placeholder expressions and which would return each of the types to be passed to multi_index::member<>?
I'm not sure what you mean here.
I've been trying different approaches but none have been successful... I'm still not grasping how to handle these placeholder expressions...
I hope the great minds on this list can bring some light in my clouded mind...
Thanks & kind regards, Peter
//-------------------------------------------------
[...snip includes...]
namespace mpl = boost::mpl; namespace bmi = boost::multi_index;
enum attributeTags { ATTR_1, ATTR_2, ATTR_3 };
template <int attrId> struct AttrTraits { typedef int type; };
Okay, AttrTraits is not a proper MPL-compatible member function, as it operates on non-type template parameters. This has problems below...
template <typename AttrT> struct Attribute { typedef AttrTraits<AttrT::value> ATraits;
typename ATraits::type value; };
template <typename AttrList> struct Object : public boost::mpl::inherit_linearly< AttrList, boost::mpl::inherit<boost::**mpl::_1, Attribute<boost::mpl::_2> >
::type {};
struct unique {}; struct non_unique {};
template <typename T> struct is_unique : boost::false_type {};
template <> struct is_unique<unique> : boost::true_type {};
template<typename ObjectT, typename IndicesMap> struct ObjectContainer { typedef typename mpl::fold< IndicesMap, mpl::vector<>, mpl::if_< is_unique<mpl::first<mpl::_2> >, mpl::push_back< mpl::_1, bmi::ordered_unique< bmi::member< Attribute<boost::mpl::second<**boost::mpl::_2> >, AttrTraits<boost::mpl::second<** boost::mpl::_2>::value>::type, &Attribute<boost::mpl::second<**boost::mpl::_2> >::value
I don't know where the "&"s came from (email problems at some point), but the ::value and ::type are, as you've observed, triggering immediate evaluation, and you want lazy evaluation. But like I mentioned above, Boost.MPL can only handle metafunctions which take type template parameters, so your use of AttrTraits is DOA. I suggest either redefine AttrTraits to take a Boost.MPL integral constant or define a wrapper that has the same effect.
// Attribute<boost::mpl::int_<0> >, // int, // &Attribute<boost::mpl::int_<0> >::value
,
mpl::push_back< mpl::_1, bmi::ordered_non_unique< bmi::member< Attribute<boost::mpl::second<**boost::mpl::_2> >, AttrTraits<boost::mpl::second<** boost::mpl::_2>::value>::type,
Ditto.
&Attribute<boost::mpl::second<**boost::mpl::_2> >::value // Attribute<boost::mpl::int_<1> >, // int, // &Attribute<boost::mpl::int_<1> >::value
::type IndexList;
typedef boost::multi_index_container<**ObjectT, IndexList> Container_t;
Container_t Container; };
[...snip main...] See if the above suggestion gets you anywhere. - Jeff

Thanks a lot jeff! It did put me on the right track... This is the compilable version. Thanks & kind regards, Peter //------------------------------------------------------------- #include <boost/mpl/if.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/inherit_linearly.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/fold.hpp> #include <boost/mpl/pair.hpp> #include <boost/mpl/push_back.hpp> #include <boost/mpl/vector.hpp> #include <boost/multi_index_container.hpp> #include <boost/multi_index/indexed_by.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> namespace mpl = boost::mpl; namespace bmi = boost::multi_index; struct ATTR_1 {}; struct ATTR_2 {}; struct ATTR_3 {}; template <typename attrT> struct AttrTraits { typedef int type; }; template <typename AttrT> struct Attribute { typedef AttrTraits<AttrT> ATraits; typename ATraits::type value; }; template <typename AttrList> struct Object : public boost::mpl::inherit_linearly< AttrList, boost::mpl::inherit<boost::mpl::_1, Attribute<boost::mpl::_2> >
::type {};
struct unique {}; struct non_unique {}; template <typename T> struct is_unique : boost::false_type {}; template <> struct is_unique<unique> : boost::true_type {}; template <typename AttrT> struct GetUnique { typedef bmi::ordered_unique< bmi::tag<AttrT>, bmi::member< Attribute<AttrT>, typename AttrTraits<AttrT>::type, &Attribute<AttrT>::value
type;
}; template <typename AttrT> struct GetNonUnique { typedef bmi::ordered_non_unique< bmi::tag<AttrT>, bmi::member< Attribute<AttrT>, typename AttrTraits<AttrT>::type, &Attribute<AttrT>::value
type;
}; template<typename ObjectT, typename IndicesMap> struct ObjectContainer { typedef typename mpl::fold< IndicesMap, mpl::vector<>, mpl::if_< is_unique<mpl::first<mpl::_2> >, mpl::push_back< mpl::_1, GetUnique<mpl::second<mpl::_2> >
, mpl::push_back< mpl::_1, GetNonUnique<mpl::second<mpl::_2> >
::type IndexList;
typedef boost::multi_index_container<ObjectT, IndexList> Container_t; Container_t Container; }; int main() { typedef boost::mpl::vector< ATTR_1, ATTR_2, ATTR_3
AttributeList_1;
typedef Object<AttributeList_1> Object_1; typedef mpl::vector< mpl::pair<unique, ATTR_1>, mpl::pair<non_unique, ATTR_2>
Object_1_Indices;
ObjectContainer<Object_1, Object_1_Indices> Object1Container; Object_1 obj1; Object1Container.Container.get<ATTR_1>().insert(obj1); return 0; } //-------------------------------------------------------------
participants (2)
-
Jeffrey Lee Hellrung, Jr.
-
Peter Nyssen