如何消除模板化基数中多个继承的typedef的歧义?

时间:2013-02-08 22:45:03

标签: c++ inheritance c++11 typedef multiple-inheritance

编辑:我正在使用tdm-gcc-4.7.1-2 for Windows

不确定如何解决此问题。我想将它用作一种类型列表,让我知道我正在尝试使用B的typedef中不存在的类型。

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?? :(

有没有办法让A<int, int>(以及A未继承的任何其他B)或其他方式让它失败?我想我可以使用tuple并递归一遍,对每个元素进行is_same比较,而不是我提供的元函数,但这看起来更容易......首先:\

3 个答案:

答案 0 :(得分:6)

这是因为类模板注入了模板名称;注入的名称可以用作模板或引用模板实例化的类型(14.6.1p1)。然后,派生类继承注入的类名(10.2p5);使用它作为模板是明确的(它是相同的模板,但它是继承的)所以是允许的。

要修复您的计划,请尝试使用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

答案 1 :(得分:2)

在§11.1/ 5中,标准说:

  

在派生类中,查找基类名称将找到   inject-name而不是作用域中基类的名称   在其中宣布。注入类名可能更少   比它所在范围内的基类名称可访问   宣布了。

因此AB范围内的注入名称。根据§14.1/ 4,它引用模板A,而不是基类(因为它不明确)。

就像A的范围一样,如果你只说A,那就是类本身(但它是这个上下文中的模板)。您正在使用此注入名称,因此名称B::A::A相同。我不认为有办法抑制这种行为。

答案 2 :(得分:2)

该标准明确允许这一点,虽然它有点令人困惑。从草案中的14.6.1-4开始:

  

查找注入类名称(10.2)的查找可能会导致   在某些情况下的歧义(例如,如果发现超过   一个基类)。如果找到所有注入的类名   引用相同类模板的特化,如果名称   后跟一个template-argument-list,引用引用   类模板本身并不是它的特化,而不是   暧昧。

[ Example: 
template <class T> struct Base { }; 
template <class T> struct Derived: Base<int>, Base<char> { 
typename Derived::Base b; // error: ambiguous 
typename Derived::Base<double> d;// OK 
}; 
— end example ]