【问题标题】:When are member functions of a templated class instantiated?模板类的成员函数何时实例化?
【发布时间】:2019-12-21 09:29:31
【问题描述】:

考虑以下示例:

template<typename T>
class Base
{
public:
  inline void fooBase ()
  {
    T t; // The following error only occurs when class ABC is not defined at the end of the file: "error: t uses undefined class ABC"
  }
protected:
};

class ABC;
class DEF;

class Derived : public Base<ABC>
{
public:
  void fooDerived ()
  {
    DEF def; // error: def uses undefined class DEF
  }
};

Derived derived;
void foo ()
{
  derived.fooBase ();
}

class ABC {};
class DEF {};

问题

  1. 为什么编译器对只在文件末尾定义的ABC 类感到满意?
  2. 为什么声明Derived时不需要定义,声明全局foo函数时也不需要定义?
  3. 模板类的成员函数何时实例化?即使该函数被显式内联,该函数似乎在foo () 中调用该函数后被实例化(在文件末尾)。
  4. 这种行为是标准 C++ 吗?如果有,是否取决于使用的 C++ 版本?

请注意,fooDerived 会按预期生成错误:在使用该类之前应(完全)定义。

请注意,没有必要单独回答所有问题,因为它们是同一问题的不同表述。

测试环境:

  • MSVC(但我对跨平台合规性感兴趣。)
  • 它似乎在三个主要编译器(GCC、CLang 和 MSVC)上工作(DEF def; 除外):https://godbolt.org/z/z_c7mc

【问题讨论】:

    标签: c++ templates class-template


    【解决方案1】:

    模板类的成员函数何时实例化?

    类模板特化的成员函数的声明与类特化一起被实例化,但定义仅在需要时才被实例化。通常在调用成员函数时。只要没有使用成员函数,定义就可能不会被实例化。

    您的示例调用了成员函数,因此必须实例化定义。

    然而,一个特化的成员函数可能有多个实例化点。一个在即将使用之前,但另一个(始终添加)位于翻译单元的末尾

    [temp.point](强调我的)

    8函数模板的特化,成员函数 模板,或类的成员函数或静态数据成员的 模板中可能有多个实例化点 翻译单元,除了实例化点 如上所述,对于任何具有以下意义的专业化 翻译单元内的实例化,翻译结束 unit 也被认为是一个实例化点。一个专业化 一个类模板在一个类模板中最多有一个实例化点 翻译单元。任何模板的特化可能有以下几点 在多个翻译单元中实例化。 如果两个不同的点 实例化赋予模板特化不同的含义 根据单定义规则,程序是非良构的,不 需要诊断。

    这让我想到了下一点,fooBase 在您展示的翻译单元中有两个实例化点。在一个ABC 不完整,而在另一个它已经完成。根据上面的段落,您的程序格式错误,不需要诊断。编译器可以对违规保持沉默,同时发出一些 似乎 可以工作的代码。但这并不能使程序有效。如果将来更新标准以要求在这种情况下进行诊断,则非法代码将无法构建。如果编译器想要诊断它,它现在甚至可能会失败。

    【讨论】:

    • 如果我理解正确,当foo() 定义在ABC 之后,即在文件末尾时,代码不会是错误的?
    • @m7913d - 你理解正确,是的。如果ABCfoo 之前完成,则程序将是良构的。
    • 那么,this answer(最后一个代码块)中的代码也是错误的?
    • @m7913d - 乍一看还不错。通常编写智能指针类型以正确处理不完整的类型。关键是要在定义任何需要完整类型的成员函数之前完成类型。在您显示的 sn-p 中,我认为没有问题。 wek_ptr 通常根本不需要完整的对象类型,短 sn-p 中的其他任何内容都不会在完成之前实例化或使用 User
    • 好的,谢谢。这只是很棘手,因为编译器不必包含错误消息。
    猜你喜欢
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多