[traits, fusion, mpl] Basic question about is_base_of and template ancestors
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
On 2012-08-30 15:10, Rindeberg Magnus wrote:
#include
#include #include #include #include #include #include struct dostuff { template<typename T> void operator()(T const & x) const { // Do stuff here! } };
template<class D> struct A { };
template
struct B { typedef T type; }; struct derived_from_A : public A
{ }; struct derived_from_B : public B
{ }; typedef ::boost::mpl::vector
::type typelist_type; ::boost::fusion::result_of::as_set
::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, ::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, ::boost::mpl::_> > (typeset_), ds); #endif } The "not" part is straight forward:
::boost::fusion::for_each( ::boost::fusion::filter_if < ::boost::mpl::not_< ::boost::is_base_of, ::boost::mpl::_> > > (typeset_), ds); I can't seem to wrap my head around an is_derived_from_b template, though. But I wonder: Why do you want to add another parameter T here? Can't you just define T inside derived_from_B? Regards, Roland
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
#include #include #include #include #include #include struct dostuff { template<typename T> void operator()(T const & x) const { // Do stuff here! } };
template<class D> struct A { };
template
struct B { typedef T type; }; struct derived_from_A : public A
{ }; struct derived_from_B : public B
{ }; typedef ::boost::mpl::vector
::type typelist_type; ::boost::fusion::result_of::as_set
::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, ::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, ::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
Thanks Roland and Jeff!
I tried the not_ <> template and I don't know why I didn't get it to work the first time. Works fine now anyway!
Also tried the "nested_template" metafunction forwarding technique but never got that to work even though I did try some variations on the theme.
So I ended up with using the "automatic deduction of template parameters" approach (suggested by Jeff and shown below) and I'm quite happy with it since it improves readability compared to the "is_base_of" template (IMHO).
Thanks again!
// Magnus
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
participants (3)
-
Jeffrey Lee Hellrung, Jr.
-
Rindeberg Magnus
-
Roland Bock