为什么类级别的typedef不能从模板中继承?

3

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

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++限制还是编译器错误。


模板类依赖于模板参数,这些参数不会自动转发。 - undefined
1个回答

5
他们实际上是“继承”的(也就是说,它们作为>的成员可访问)。然而,所有从依赖基类(即依赖于模板参数的基类)继承的成员(不仅仅是类型)只有在编译器有理由相信它们是依赖项时,才会在类模板内查找。
换句话说,在解析模板c2的定义时,编译器不知道在实例化时t将是什么,因此它没有手段猜测c1的定义将是什么(请记住,它可能稍后被专门化)。因此,在查找c2中发现的名称时,它根本不查看c1。所以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不是模板时,在解析时已完全知道它的所有基类的定义,因此查找名称没有问题。
您可以在这个与此相关的 SO 问题中了解更多有关这两阶段查找的详细信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接