编辑:我正在使用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
比较,而不是我提供的元函数,但这看起来更容易......首先:\
答案 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而不是作用域中基类的名称 在其中宣布。注入类名可能更少 比它所在范围内的基类名称可访问 宣布了。
因此A
是B
范围内的注入名称。根据§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 ]