Boost logo

Boost Users :

Subject: Re: [Boost-users] [traits, fusion, mpl] Basic question about is_base_of and template ancestors
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2012-09-02 13:11:49


On Thu, Aug 30, 2012 at 6:10 AM, Rindeberg Magnus <
magnus.rindeberg_at_[hidden]> 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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net