为什么类级别的typedef不是从tempates继承的?

时间:2015-10-15 14:21:18

标签: c++ templates inheritance typedef

我的问题是,为什么以下代码无法编译:

template<typename t> class c1
{
public:
    typedef int type_name;
    void fn1(type_name x) {}
};

template<typename t> class c2 : public c1<t>
{
public:
    void fn2(type_name x) {}
};

虽然如下:

class c1
{
public:
    typedef int type_name;
    void fn1(type_name x) {}
};

class c2 : public c1
{
public:
    void fn2(type_name x) {}
};

如您所见,唯一的区别是在第一种情况下,类是模板。 Gcc和Clang抱怨在第二个类中没有定义type_name(仅在模板版本中)。 typedef是不是从父类继承的?如果是这样,为什么它适用于非模板版本?从模板中使用typedef时是否有异常?

另外,我知道我可以使用完全限定的类型名称,即'typename c1 :: type_name'。我只是想知道这是否是一些C ++限制或编译器错误。

1 个答案:

答案 0 :(得分:3)

他们 实际上&#34;继承&#34; (我的意思是他们可以作为c2<t>的成员访问)。但是,当编译器有理由相信它们依赖时,所有从依赖基类(依赖于模板参数的基类)继承的成员(不仅仅是类型)都只在类模板中查找。

换句话说,在解析模板c2的定义时,编译器在实例化时不知道t将是什么,因此它无法猜测定义是什么c1<t>将是(记住它可以在以后专门化)。因此,当查找c1中找到的名称时,它根本不会查看c2。所以找不到type_name

但是,如果您以某种方式明确地依赖于模板参数进行名称查找,则编译器将意识到它必须推迟查找直到实例化。在这些情况下会发生这种情况:

// Case 1
template<typename t> class c2 : public c1<t>
{
public:
    void fn2(typename c1<t>::type_name x) {}
};

// Case 2
template<typename t> class c2 : public c1<t>
{
public:
    void fn2(typename c2::type_name x) {}
};

在这两种情况下,::左侧的内容取决于模板参数,因此编译器会知道推迟查找直到实例化。

另请注意,您需要添加typename关键字;没有它,编译器就不知道::右边的东西是类型还是非类型成员。在这种情况下,语言标准要求将其视为非类型成员,这会导致语法错误。

但是,当c2不是模板时,所有基类的定义在解析时都是完全已知的,因此查找名称没有问题。

您可以在此somewhat related SO question中了解有关此两阶段查找的更多详细信息。

相关问题