【发布时间】:2021-01-07 15:17:46
【问题描述】:
一个“普通”函数,当在单个翻译单元中单独定义和使用时,声明和定义如下:
// implementation.cpp
static void fun(int arg) { /* implementation */ }
或者,您可以删除 static 关键字并将函数包装在 未命名的命名空间中。但如果不执行上述任一操作可能会导致 ODR 违规:如果不同的翻译单元也具有 fun 的声明/定义(具有相同的参数),则喜欢者可能不得不默默地丢弃一个的实现以保持单一定义(在这种情况下,您最好为两者拼写完全相同的定义,否则您会看到意外行为)。
如上所述,问题更“面向实现”,但即使是标准也会敦促您使用static 或namespace { /**/ } 来防止此类副作用。
问题是当fun 是函数模板时会发生什么?我是否还需要将其包装在未命名的命名空间中或在翻译单元中将其声明为静态?
template <class T>
/* static ? */ void fun(T arg) { /*...*/ }
在 cppreference 中提到,如果函数是 inline 显然没问题(对单一定义的要求仅针对非内联函数提出),因此无需担心 ODR:
每个非内联函数的一个且只有一个定义或 odr 使用的变量(见下文)必须出现在 整个程序
我们知道函数模板是内联的,但这足以保证 ODR 的正确性吗?
【问题讨论】:
-
您的报价是非内联函数和变量的单一定义规则。请继续阅读后面的段落,了解内联函数的要求。 (不,定义不会消失。
inline关键字与直接使用函数内容无关,也就是内联函数。) -
@JaMiT 所以我应该使用静态还是将其放在未命名的命名空间中? (我将编辑引用之前的文本,以更好地连接 inline 和 non 之间的点)
-
您可以拥有任意数量的模板实例。链接器将占用一个,一切正常。我们在不同的编译单元中实例化多个实例是正常的用例。这种情况没什么特别的。
-
@Klaus 显然,当另一位作者尝试在不同的翻译单元中将
fun声明为其他内容时,问题就会出现。这也是在非模板情况下发生的情况(如果我们有一个简单的情况,只有一个main.cpp没有多少人使用未命名的命名空间)。我不是在询问多个实例化,但最佳实践是什么,我应该主动将其声明为静态吗?如果不同的翻译单元包含`templatefun(T arg) { /* 这里不同的实现*/ } 会不会有(n ODR) 问题? -
好的,你的意思是说:“其他人”将在不同的文件中创建一个具有相同签名的模板函数,并在不同的编译单元中使用它。好的。但是,如果您担心这些事情,您也应该担心其他人也会创建具有不同内容的命名空间并添加其他违反 ODR 的内容。抱歉,但这看起来不像是技术问题,而是与项目管理、审查和文档有关的问题。如果发生这种情况,例如,您如何定义包含订单?只有我的两分钱
标签: c++ templates one-definition-rule