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

时间:2019-12-21 09:29:31

标签: c++ templates class-template

考虑以下示例:

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

1 个答案:

答案 0 :(得分:1)

  

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

类模板专门化的成员函数的声明与该类专门化一起被实例化,但是定义仅在需要时被实例化。通常在调用成员函数时。只要不使用成员函数,该定义就可能无法实例化。

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

但是,专业化的成员函数可能有多个实例化点。一个在即将使用之前,但在翻译单元的末尾又添加了一个(总是添加)

  

[温度点] (强调我的意思)

     

8函数模板的一种特殊化,即成员函数   模板,或类的成员函数或静态数据成员的   模板在一个模板中可能具有多个实例化点   翻译单元,以及实例化要点   如上所述,对于任何具有以下特点的专业化   翻译单元内的实例化,翻译结束   单元也被视为实例化点。专为   一个类模板在一个模板中最多具有一个实例化点   翻译单位。任何模板的专业化可能都有以下几点   在多个翻译单元中实例化。 如果有两个不同的观点   实例化赋予模板专业化不同的含义   根据一定义规则,程序格式错误,没有   需要诊断。

这将我带到下一点,fooBase在您显示的翻译单元中有两个实例化点。一个ABC不完整,而另一个var regex = new Regex(@"=\s*(?<Number1>\d*),\s*Num2\s*=\s*(?<Number2>\d*)"); var matches = regex.Match(text); if(matches.Success) { var num1 = Int32.Parse(matches.Groups["Number1"].Value); var num2 = Int32.Parse(matches.Groups["Number2"].Value); } 已经完成。在上面的段落下,您的程序格式错误,不需要诊断。编译器可以对违规保持沉默,同时发出似乎可以正常工作的一些代码。但这不能使程序有效。如果将来会更新标准以在这种情况下需要诊断,则非法代码将无法构建。如果编译器希望对其进行诊断,它甚至可能现在失败。