问题 编译的程序是否可能不包含实例化的模板类?


考虑以下代码:

template <typename T>
class A {
    T x;
    // A bunch of functions
};

std::size_t s = sizeof(A<double>);

假设 sizeof 运算符是唯一一个实例化的地方 A<double> 是必须的。编译的程序是否可能  包含相关代码 A<double> (例如。 A<double>::~A())?


2523
2017-12-30 10:10


起源

只要程序的可观察行为符合标准,绝对一切都是可能的。 - n.m.
@牛米。实例化点可以改变可观察的行为。 - Oliv
@Oliv Instantiation不需要生成或包含任何特定的目标代码。 - n.m.
@牛米。那些歌曲就像是关于本体论的争论的开始!你在谈论没有的实例化吗? 存在。 (存在的词源,拉丁语ex(s)istere,表现出来,出现) - Oliv
@Oliv我说的是用正确的词来命名正确的东西。实例化是将函数模板(来自C ++语言的概念)转换为函数(与C ++语言不同的概念)或将类模板转换为类的过程。然后该功能是否变成机器代码指令(不 来自C ++语言的概念)是一个与模板或C ++语言的任何其他部分没有直接关系的问题。它是关于编译器如何消除未使用的代码。 - n.m.


答案:


该类将被实例化,但编译器不能实例化任何成员函数定义,[temp.inst] / 1:

[...]类模板专业化是 隐式实例化时 专业化在上下文中被引用 需要完全定义的对象类型[...]

[temp.inst] / 2:

类模板特化的隐式实例化导致了 声明的隐式实例化,而不是定义的实例化,默认参数或noexcept-specifiers 类成员函数,[...]


12
2017-12-30 10:22



这是编译器的情况 一定不 实例。它不是编译器的选择。 - MSalters
@MSalters你的意思是将“不会实例化任何成员定义”改为“不能实例化......”是合适的吗? - Oliv
我认为值得强调的是你可以依赖这种行为。你没有错,但问题是假设这两种行为都是可能的。 - MSalters
好的,我明白,有一些着名的编译器不符合标准,特别是在这个主题上。我做了一个编辑。 - Oliv
你的意思是符合标准的编译器会 决不 生成类的实例化? - iBug


编译的程序是否可能不包含相关代码 A<double> (例如。 A<double>::~A())?

当然有可能。

std::size_t s = sizeof(A<double>);

只是一个编译时操作,不需要任何运行时实例 A<double>,所以不需要构造函数,析构函数或其他 相关代码


即使存在如下模板函数代码的显式实例化

 if(sizeof(A<double>) <= 4) {
      A<double> a; // Instantiation of constructor and destructor
      a.x = 3.5;
 }

允许编译器优化该代码。


2
2017-12-30 10:14





是的,sizeof()不需要成员函数,因此很可能不会生成它们。所有sizeof需求都是数据成员。


0
2017-12-30 10:14





我已经构建了这段代码:

#include <cstddef>


template <typename T>
class A {
    T x;
    // A bunch of functions
};


int main(const int argc, const char* argv[])
{
    std::size_t s = sizeof(A<double>);
}

并启动objdump我得到这个输出:

$ objdump -t a.out 

a.out:  file format Mach-O 64-bit x86-64

SYMBOL TABLE:
0000000100000000 g     F __TEXT,__text  __mh_execute_header
0000000100000f90 g     F __TEXT,__text  _main
0000000000000000         *UND*  dyld_stub_binder

我们可以看到没有生成与构造函数/析构函数关联的符号。


0
2017-12-30 11:52