2013-02-08 49 views
9

编辑:我正在使用tdm-gcc-4.7.1-2 for Windows如何从模板化的基础中消除多个继承的typedefs?

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

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继承S),或另一种方式来进行此事?我想我可以使用一个tuple并缓解我的方式,对每个元素进行is_same比较,无论我是否提供元函数,但这似乎更容易...首先:\

+0

我怀疑'B ::一个 :: type'应该编译在所有...'B :: A'已经是模糊的,不参照模板,但从中'B'导出实例... – 2013-02-08 22:49:34

+0

@DavidRodríguez-dribeas我同意的一个,我不明白为什么它编译。我可能错过了埋在标准中的规则。 – 2013-02-08 22:57:53

+0

我相信C++ 11草案中的章节是14.6.1-4。明确地允许这种情况 – jmetcalfe 2013-02-08 23:04:15

回答

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 
+0

在基地检查好电话! :D谢谢。 – 2013-02-11 14:31:50

2

在§11.1/ 5中,标准说:

在派生类中,基类名的查找就会发现,而不是在它被宣布范围 基类的名称 注入的类名。注入的类名称可能比其声明范围内的基类名称的可访问性要低 。

所以A是在B范围内注入的名称。它指的是模板A,而不是根据§14.1/ 4的基类(因为它不明确)。

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

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 ]