Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disambiguate multiple inherited typedefs from templated bases?

Edit: I'm using tdm-gcc-4.7.1-2 for Windows

Not sure how to resolve this. I'd like to use this as a sort of type list that will let me know I'm attempting to use a type not present in B's typedefs.

template <typename T, typename U>
struct A {
    typedef pair<T, U> type;
};

struct B : A<int, string>, A<int, float> {};

B::type foo; // won't compile, ambiguous reference, as expected
B::A<int, int>::type bar; // compiles fine?? :(

Is there a way to get it to fail on A<int, int> (and any other A's not inherited by B), or another way to go about this? I guess I could use a tuple and recurse my way through it, doing an is_same comparison on each element vs whatever I feed the metafunction, but this seemed easier... at first :\

like image 767
Brett Rossier Avatar asked Feb 08 '13 22:02

Brett Rossier


2 Answers

This happens because class templates have their template-name injected; the injected name can be used either as a template or a type referring to the template instantiation (14.6.1p1). The injected class name is then inherited by the derived class (10.2p5); using it as a template is unambiguous (it's the same template however it is inherited) so is allowed.

To fix your program, try using is_base_of:

struct B : A<int, string>, A<int, float> { };
template<typename T, typename U>
using check_A = typename std::enable_if<std::is_base_of<A<T, U>, B>::value, A<T, U>>::type;

check_A<int, float>::type bar1; // compiles
check_A<int, int>::type bar2; // error
like image 110
ecatmur Avatar answered Oct 21 '22 01:10

ecatmur


In §11.1/5, the Standard says:

In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared.

So A is an injected name in the scope of B. It refers to the template A, not the base class (because it would be ambiguous) according to §14.1/4.

Just like in the scope of A, if you say just A, it's the class itself (but it's the template in this context). You're making use of this injected name, and so the name B::A is the same as ::A. I don't think there's a way to suppress this behaviour.

like image 40
Seth Carnegie Avatar answered Oct 21 '22 00:10

Seth Carnegie