I tried googling this with no luck, so I'm trying here.
I have a couple of classes, each of which defines a member struct foo
. This member type foo
can itself inherit from one of the former classes, hence obtaining a member type foo
itself.
I want to access the nested foo
types using template metaprogramming (see below), but c++ name injection introduces problems, as the upper foo
type name gets injected into the lower foo
type, and the upper one gets resolved when I want to access the lower, say using A::foo::foo
.
Here is an example:
#include <type_traits>
struct A;
struct B;
struct A {
struct foo;
};
struct B {
struct foo;
};
struct A::foo : B { };
struct B::foo : A { };
// handy c++11 shorthand
template<class T>
using foo = typename T::foo;
static_assert( std::is_same< foo< foo< A > >, foo< B > >::value,
"this should not fail (but it does)" );
static_assert( std::is_same< foo< foo< A > >, foo< A > >::value,
"this should fail (but it does not)" );
FYI, I'm implementing function derivatives, foo
is the derivative type. The above situation happens e.g. with sin/cos.
TLDR: how do i get foo<foo<A>>
to be foo<B>
, not foo<A>
?
Thanks !
This is not really an automatic solution but solves the problem. Your types provide a typedef to the base class, absence/presence of this typedef is detected through SFINAE and the nested foo is found either through the base or through normal look-up.
You can probably automate the has_base
to check a list of known
bases with is_base_of
if you need more automation.
#include <type_traits>
template <typename T>
struct has_base
{
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::base*);
template <typename>
static no& test(...);
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
struct A {
struct foo;
};
struct B {
struct foo;
};
struct A::foo : B { typedef B base; };
struct B::foo : A { typedef A base; };
template<typename T, bool from_base = has_base<T>::value >
struct foo_impl {
typedef typename T::base::foo type;
};
template<typename T>
struct foo_impl<T, false> {
typedef typename T::foo type;
};
template<typename T>
using foo = typename foo_impl<T>::type;
static_assert( std::is_same< foo< foo<A> >::, foo< B > >::value,
"this should not fail (but it does)" );
static_assert( std::is_same< foo< foo< A > >, foo< A > >::value,
"this should fail (but it does not)" );
int main()
{
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With