考虑以下示例(在同一翻译单元中):
inline void f();
void f() {}
重新宣布f
时会发生什么?f
还算inline
吗?
我查看了这种情况的标准,但我只在 10.1.6/6 [dcl.inline] 中找到了相反的情况:
[...]如果函数或变量的定义出现在翻译单元中,然后才将其首次声明为内联,则程序格式不正确。[...]
我想要标准中的一些参考资料,以指定在这种情况下会发生什么。
我看到了这篇文章,但它没有在标准中显示明确的参考。我倾向于相信没有这样的参考。
重新声明
f
时会发生什么?f
还算inline
吗?
是的,f
仍然被认为是inline
.
标准中与inline
函数说明符语义相关的部分可以在[dcl.fct.spec]中找到:
函数声明...使用
inline
说明符声明内联函数。inline
说明符向实现指示,在调用点对函数体进行内联替换比通常的函数调用机制更可取。内联函数应在使用它的每个翻译单元中定义,并且在每种情况下都应具有完全相同的定义([basic.def.odr])。[注意:在内联函数的定义出现在翻译单元中之前,可能会遇到对内联函数的调用。 —尾注] 如果函数的定义出现在翻译单元中,然后才将其第一次声明为内联,则程序格式不正确。如果具有外部链接的功能在一个翻译单元中声明为内联,则应在出现该函数的所有翻译单元中声明为内联;无需诊断。具有外部链接的
inline
职能在所有翻译单元中应具有相同的地址。
在[basic.def.odr]中:
每个程序应只包含该程序中使用的每个非内联函数或变量的一个定义
另请参阅 [dcl.stc]/8 中的示例:
void h(); inline void h(); // external linkage inline void l(); void l(); // external linkage
所有内容的解释是:
inline
作为函数说明符充当标志,表达您希望对给定函数的调用内联。一旦在某个函数声明中遇到它,它就会为该特定函数重载保持"设置",并且无法"取消设置"它。在声明或函数定义上指定
inline
并不重要,因为定义也是声明,并且允许多个声明。
但是,必须在函数定义之前或函数定义之前以及 odr 使用之前遇到inline
说明符(odr-use意味着编译器需要实际发出调用函数的代码,或者出于任何原因需要其地址)。inline
说明符对函数的链接没有影响,对于非静态全局函数,函数的链接仍然是外部的。如果获取inline
函数(具有外部链接)的地址,编译器将为其发出一个外联定义,确保链接器可以在必要时折叠多个定义(例如使用弱符号)。这样,不同 TU 中inline
函数的地址将是相同的。一旦一个函数被声明为
inline
并具有外部链接,就必须在使用它的所有其他翻译单元中inline
声明它。您必须在 odr 使用的每个翻译单元中提供
inline
函数的定义,并且它必须完全相同。
重新声明的效果在 [basic.def]/1 中指定
声明可以将一个或多个名称引入翻译单元,或重新声明先前声明引入的名称。如果是这样,声明将指定这些名称的解释和属性。[...]
因此,通过重新声明,可以为名称添加规范,但不能删除它们。