On Thu, Aug 30, 2012 at 6:10 AM, Rindeberg Magnus <magnus.rindeberg@volvo.com> wrote:
Hello List!
I have an issue understanding how to combine CRTP with the "is_base_of" trait when iterating over a fusion vector. I have tried to illustrate my problem in the test program below. The idea is to first "do stuff" to all instances of types derived from A and then "do stuff" to the ones derived from B. I just don't know what to write instead of "WHAT_GOES_HERE?" below. I have tried to use "::boost::mpl::_" in different ways to get the "type" type of B but failed miserably every time.
I'm also curious about how to negate the "is_base_of" predicate. I tried using "not_<>" but that didn't work at all...
Very thankful for any and all help!
// Magnus
P.S. Sorry if this question has been answered already! I have looked at the documentation, searched archives and the web but couldn't find the solution. Maybe I searched using the wrong keywords...
#include <boost/type_traits.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/container.hpp>
#include <boost/fusion/include/at_key.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/filter_if.hpp>
struct dostuff
{
template<typename T>
void
operator()(T const & x) const
{
// Do stuff here!
}
};
template<class D>
struct A
{
};
template<class D, typename T>
struct B
{
typedef T type;
};
struct derived_from_A : public A<derived_from_A>
{
};
struct derived_from_B : public B<derived_from_B, int>
{
};
typedef ::boost::mpl::vector<derived_from_A, derived_from_B>::type typelist_type;
::boost::fusion::result_of::as_set<typelist_type>::type typeset_;
int
main(int argc, char ** argv)
{
dostuff ds;
// This seems to be working!
::boost::fusion::for_each(
::boost::fusion::filter_if
< ::boost::is_base_of<A< ::boost::mpl::_>, ::boost::mpl::_>
> (typeset_), ds);
#if(0)
// Don't know how to do this! Preferably I'd like to check for inheritance from B.
// If that isn't possible I'll settle for "not inheriting from A".
::boost::fusion::for_each(
::boost::fusion::filter_if
< ::boost::is_base_of<B< ::boost::mpl::_, WHAT_GOES_HERE? >, ::boost::mpl::_>
> (typeset_), ds);
#endif
}
In this particular instance, I think you can get away with replacing WHAT_GOES_HERE? with
nested_type< ::boost::mpl::_ >
where
template< class T > struct nested_type : T { }; // metafunction forwarding
Or, there may be something equivalent already in Boost.MPL that grabs the nested "type" typedef.
Hmmm...on second inspection, that will probably error out when you apply it to to derived_from_A, since derived_from_A doesn't have a nested "type" typedef. So, you'll have to dispatch nested_type depending on whether its argument has a nested type or not :/ I think you can use a Boost.MPL macro to help with that, something like BOOST_MPL_HAS_XXX. I believe there's also a recent extension to Boost.TypeTraits that does something equivalent.
A more general solution that accounts for cases where you might not have a direct mapping from the derived class to the base class instantiation, and which may still be preferable in this case, is to automatically deduce the template parameters (or, optionally, some subset of them) for the B template (warning: untested):
struct yes_tag { char _[42]; };
struct no_tag { char _[1]; };
template< class T > T* declptr();
template< class T >
struct is_B_base_of
{
template< class D, class U >
static yes_tag test(B<D,U>*);
static no_tag test(...);
static bool const value = sizeof( test(declptr<T>()) ) == sizeof( yes_tag );
typedef is_B_base_of type;
};
Or something like that. Hope that gives you some ideas,
- Jeff