问题 实例化点可以延迟到翻译单元结束吗?


考虑以下小代码片段:

#include <iostream> 

template<class T> 
int test(); 

int main() 
{     
    std::cout << test<int>() << "\n"; 
} 

// POI for test<int>() should be right here      

template<class T> 
int test() 
{ 
    return 0; 
}

实例 为Clang和g ++编译和打印0。

这是 标准草案 引用功能模板的实例化

14.6.4.1实例化点[temp.point]

1对于函数模板特化,成员函数模板特化或特化   如果专门化是隐式实例化的,则为类模板的成员函数或静态数据成员   因为它是从另一个模板专门化和引用它的上下文中引用的   取决于模板参数,专业化的实例化点是   封闭专业化的实例化。否则,这种专业化的实例化点   紧跟在引用特化的命名空间范围声明或定义之后。

Vandevoorde和Josuttis 有以下说法:

在实践中,大多数编译器会延迟实际的实例化   非翻译功能模板到翻译单元的末尾。这个   有效地移动相应模板的POI   专业化到翻译单元的末尾。意图   C ++语言设计者认为这是一个有效的实现   技术,但标准并未明确这一点。

:Clang / g ++不符合规定,因为它们将POI延迟到翻译单元的末尾?


7195
2018-04-12 12:30


起源

从你粘贴的报价: 标准没有说清楚,所以我认为你不能有一个有效的答案,除非你找到一种方法来使标准清晰。 - mah
@TemplateRex我引用的段落也在C ++ 11中。它 允许 仅在一个POI处实例化并且基本上忽略其他POI。结合在TU末尾添加(允许)另一个POI的C ++ 11“放松”,应该允许clang ++ / g ++的行为。 (顺便说一句,那些问题有锚点,所以你可以附加一个 #993 到URL; wg21.cmeerw.net/cwg/issue993 也有可能)) - dyp
@TemplateRex Vandervoorde和Josuttis在哪里说的?这与我的理解不符。记住我引用的段落,它表示函数模板只需要在TU中的某个地方定义,它不必在实例化点之前。实例化的点修改了生成的特化能够看到的内容(如果您在TU的末尾声明了一个函数,并以依赖的方式在模板中使用它,那么您可以使用该事实来确定POI clang使用的内容) 。 - Johannes Schaub - litb
从概念上讲,甚至是 时间 根据2.2p8(“检查每个翻译的翻译单元以生成所需实例化列表。[...]所需模板的定义位于[...]所需模板的实例化后,在所有TU完成处理之后。[...] 。]执行所有必需的实例化以生成实例化单元。“)。实现简化了这个过程(根据as-if和脚注p11“实现必须表现得好像这些单独的阶段发生,尽管在实践中不同的阶段可能会折叠在一起。”)。 - Johannes Schaub - litb
@TemplateRex [temp.inst] / 8“如果需要隐式实例化类模板特化并声明模板但未定义模板,则程序格式不正确。”据我所知,功能模板没有这样的规则。 - dyp


答案:


核心工作组缺陷报告993 是为了解决这个问题而创建的:

993.在翻译单位结束时自由进行实例化

条:14.6.4.1 [temp.point]状态:C ++ 11发布者:John Spicer日期:2009年3月6日
[2011年3月会议上投票支持WP。]

目的是在翻译单元的末尾而不是实际的实例化点进行模板实例化是一种允许的实现技术。然而,这个想法并没有反映在现行规则中。

拟议决议(2011年1月):

更改14.6.4.1 [临时点]第7段如下:

函数模板,成员函数模板或类模板的成员函数或静态数据成员的特化可以在翻译单元中具有多个实例化点, 除了上述实例化点之外,对于在翻译单元内具有实例化点的任何这种专业化,翻译单元的末尾也被认为是实例化的点。 类模板的专业化......

C39 11中的第14.6.4.1/7段在N3936中是14.6.4.1/8:

功能模板,成员函数模板或成员函数或静态的专门化   类模板的数据成员可以在翻译单元内具有多个实例化点,以及   除了上面描述的实例化点之外,对于任何具有重点的专业化   在翻译单元内的实例化中,翻译单元的末尾也被认为是一个点   实例。类模板的专门化在翻译中最多只有一个实例化点   单元。任何模板的专门化可以在多个翻译单元中具有实例化点。如果   两个不同的实例化点给出了模板特化根据一个不同的含义   定义规则(3.2),程序格式错误,无需诊断。

所以,是的,允许实现将模板实例化的时间延迟到翻译单元的末尾。


7
2018-04-12 13:55



感谢@TemplateRex 找到缺陷报告 这清楚地表明,这一变化是专门为了使问题中观察到的行为成为可能而引入的。 - Casey
tnx用于编写它。事后来看,我觉得在发布之前没有搜索过“翻译单元结束”有点傻 - TemplateRex


显式调用模板后显式特殊化将在编译时失败。

#include <iostream> 

template<class T> 
int test(T y);


int main() 
{     
    std::cout << test<int>(0) << "\n"; 
}

template<class T> 
int test(T y) 
{ 
    return 0; 
}

// POI for test<int>() should be right here      

template<>
int test(int y) 
{ 
    return 2; 
}

检查编译错误 这里

Compilation error    time: 0 memory: 0 signal:0
prog.cpp:21:15: error: specialization of ‘int test(T) [with T = int]’ after instantiation
int test(int y) 

3
2018-04-12 13:23



在模板中说,a 专业化 是实例化模板的结果。你的程序包括一个 明确的专业化 的 test 功能模板。 - Casey