我刚刚读到constexpr和内联函数遵循一个定义规则,但它们的定义必须相同。所以我尝试了一下:
inline void foo() {
return;
}
inline void foo() {
return;
}
int main() {
foo();
};
错误:"void foo()"的重新定义,
和
constexpr int foo() {
return 1;
}
constexpr int foo() {
return 1;
}
int main() {
constexpr x = foo();
};
错误:"constexpr int foo()"的重新定义
那么,constexpr和内联函数究竟意味着什么可以服从ODR呢?
我刚刚读到constexpr和内联函数遵循一个定义规则,但它们的定义必须相同。
这是对不同翻译单元中的内联函数的引用。在您的示例中,它们都在同一个翻译单元中。
这在C++标准草案3.2
一个定义规则[basic.def.odr]中有介绍,其中写道:
类类型(第9条)、枚举类型(7.2)、内联函数可以有多个定义外部链接(7.1.2)、类模板(第14条)、非静态函数模板(14.5.6)、静态数据成员类模板的成员函数(14.5.1.1),或如果每个定义出现在不同的翻译单元中,前提是定义满足以下要求。鉴于这样一个名为D的实体在多个翻译单元中定义,然后是
包括以下项目符号:
- D的每个定义应由相同的令牌序列组成;以及
在一个翻译单元中重复定义函数。这总是被禁止的:
任何翻译单元都不得包含任何变量、函数、类类型、枚举的多个定义类型或模板。(C++11 3.2/1)
对于inline
函数,您可以在多个转换单元(读取:.cpp文件)中以完全相同的方式定义相同的函数。事实上,必须在每个翻译单元中定义它(通常通过在头文件中定义它来完成):
内联函数应在其使用的每个翻译单元中定义。(C++11 3.2/3)
对于具有外部链接(非静态)函数的"正常"(非内联、非constexpr、非模板等)函数,这通常(不需要诊断)会导致链接器错误。
每个程序应包含odr使用的每个非内联函数或变量的一个定义在该项目中;无需诊断。(C++11 3.2/3)
综上所述:
- 永远不要在一个翻译单元中多次定义任何内容(它是.cpp文件和所有直接或间接包含的头)
- 您可以将一定数量的内容放入头文件中,这些内容将被包含在几个不同的翻译单元中一次,例如:
inline
功能class
型和template
s- CCD_ 6是CCD_
如果您有:
file1.cpp:
inline void foo() { std::cout << "Came to foo in file1.cpp" << std::endl; }
和
file2.cpp:
inline void foo() { std::cout << "Came to foo in file2.cpp" << std::endl; }
并且在可执行文件中将这些文件链接在一起,则违反了one-definition-rule
,因为inline
函数的两个版本不相同。