9

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

不知道如何解决这个问题。我想将其用作一种类型列表,让我知道我正在尝试使用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?? :(

有没有办法让它失败A<int, int>(以及任何其他A不被继承的B),或者另一种方法来解决这个问题?我想我可以使用 atuple并通过它递归,is_same对每个元素与我提供的元函数进行比较,但这似乎更容易......起初:\

4

3 回答 3

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
于 2013-02-08T23:17:18.910 回答
2

在 §11.1/5 中,标准说:

在派生类中,基类名称的查找将在声明它的范围内找到注入类名称而不是基类的名称。在声明它的范围内,注入的类名可能比基类的名称更难访问。

A.范围内的注入名称也是如此B。根据§14.1/4,它指的是模板A,而不是基类(因为它会模棱两可)。

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

于 2013-02-08T23:06:34.253 回答
2

该标准明确允许这样做,尽管它有点令人困惑。从草案 14.6.1-4 开始:

查找注入类名称 (10.2) 的查找在某些情况下可能会导致歧义(例如,如果在多个基类中找到它)。如果找到的所有注入类名称都引用同一类模板的特化,并且如果名称后跟模板参数列表,则引用是指类模板本身而不是其特化,并且不是模棱两可的。

[ 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 ]
于 2013-02-08T23:07:02.060 回答