【问题标题】:Why are class-level typedefs not inherited from tempates?为什么类级别的 typedef 不是从模板继承的?
【发布时间】:2015-10-15 14:21:18
【问题描述】:

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

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

【问题讨论】:

  • 嗯,模板类依赖于模板参数,不会自动转发。

标签: c++ templates inheritance typedef


【解决方案1】:

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

也就是说,在解析模板c2的定义时,编译器在实例化的时候并不知道t会是什么,所以它无法猜测c1&lt;t&gt;的定义会是什么(请记住,它可以在以后专门化)。因此,在查找在 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不是模板时,它的所有基类的定义在解析时是完全已知的,所以查找名称没有问题。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    相关资源
    最近更新 更多