;普通的";当在单个翻译单元中定义和使用时,函数的声明和定义如下:
// implementation.cpp
static void fun(int arg) { /* implementation */ }
或者,您可以删除static
关键字,并将函数包装在未命名的命名空间中。但是,如果不执行上述操作之一,可能会导致ODR违规:如果不同的翻译单元也有fun
的declaratino/definition(具有相同的参数(,则相似的翻译单元可能不得不默默地放弃其中一个实现,以保留一个定义(在这种情况下,最好为两者拼写完全相同的定义,否则会出现意外行为(。
如上所述;"面向实现";,但即使是标准也会敦促您使用CCD_ 3或CCD_。
问题是当fun
是函数模板时会发生什么?我应该还要求将它包装在一个未命名的命名空间中,还是在翻译单元中将其声明为静态
template <class T>
/* static ? */ void fun(T arg) { /*...*/ }
在cppreference中提到,如果函数是inline
,那么它显然是可以的(对单个定义的要求只针对非内联函数提出(,因此没有ODR担心:
每个非内联函数或odr使用的变量(见下文(必须出现在整个程序
我们知道函数模板是内联的,但这足以保证ODR的正确性吗?
在cppreference中提到,如果一个函数(具有外部链接(标记为inline
,则必须格外小心,因为该定义必须存在于使用该函数的每个转换单元中。当有多个定义时,必须满足几个条件,包括:
每个定义都由相同的令牌序列组成
如果不满足此要求,则表示程序格式错误,不需要诊断。此要求同样适用于内联函数和函数模板。有时这会很好,但如果编译器选择不内联对函数的调用(inline
关键字不会影响这一点(,那么最终可能会调用错误版本的函数。不需要链接器来检测此情况。
事实上,这是链接者往往会默默忽略的ODR违规。尽管问题中声称了什么,但当具有外部链接的非内联函数有多个定义时,链接器往往会产生错误并中止。
注意:标记函数static
或将其封闭在匿名命名空间中将导致它不再具有外部链接。
我想注意的是,这个问题使用了单词";显然";以一种相当常见但不标准的方式表示";我需要以下虚假陈述是真的,所以毫无疑问地接受它"当你觉得有必要为某事辩护时,学会停下来并扭动自己是很有用的;显而易见";。