对于内联函数和 constexpr 函数,"obey ODR" 是什么意思?
What means "obey ODR" in case of inline and constexpr function?
我刚读到 constexpr 和 inline 函数遵循一个定义规则,但它们的定义必须相同。所以我试试看:
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和inline函数到底是什么意思可以服从ODR?
I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical.
这是针对不同翻译单元中的内联函数。在您的示例中,它们都在同一个翻译单元中。
这在 draft C++ standard 3.2
一个定义规则 [basic.def.odr] 中包含:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements. Given
such an entity named D defined in more than one translation unit, then
并包括以下项目符号:
- each definition of D shall consist of the same sequence of tokens; and
您在一个翻译单元中重复定义函数。这总是被禁止的:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration
type, or template. (C++11 3.2/1)
对于 inline
个函数,您可以在多个翻译单元(阅读:.cpp 文件)中以完全相同的方式定义相同的函数。事实上,您必须在每个翻译单元中定义它(通常通过在header文件中定义它来完成):
An inline function shall be defined in every translation unit in which it is odr-used. (C++11 3.2/3)
对于"normal"(non-inline、non-constexpr、non-template等)具有外部链接(non-static)函数的函数,这通常会(无需诊断)导致链接器错误。
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. (C++11 3.2/3)
总结一下:
- 切勿在一个翻译单元中多次定义任何内容(这是一个 .cpp 文件,所有内容都直接或间接包含 headers)。
- 您可以将一定数量的东西放入 header 文件中,它们将在几个不同的翻译单元中被包含 一次,例如:
inline
函数
class
类型和 template
s
static
个 class template
的数据成员。
如果你有:
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; }
而你 link 将这些文件放在一个可执行文件中,你违反了 one-definition-rule
因为 inline
函数的两个版本不相同。
我刚读到 constexpr 和 inline 函数遵循一个定义规则,但它们的定义必须相同。所以我试试看:
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和inline函数到底是什么意思可以服从ODR?
I just read that constexpr and inline functions obey one-definition rule, but they definition must be identical.
这是针对不同翻译单元中的内联函数。在您的示例中,它们都在同一个翻译单元中。
这在 draft C++ standard 3.2
一个定义规则 [basic.def.odr] 中包含:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
并包括以下项目符号:
- each definition of D shall consist of the same sequence of tokens; and
您在一个翻译单元中重复定义函数。这总是被禁止的:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template. (C++11 3.2/1)
对于 inline
个函数,您可以在多个翻译单元(阅读:.cpp 文件)中以完全相同的方式定义相同的函数。事实上,您必须在每个翻译单元中定义它(通常通过在header文件中定义它来完成):
An inline function shall be defined in every translation unit in which it is odr-used. (C++11 3.2/3)
对于"normal"(non-inline、non-constexpr、non-template等)具有外部链接(non-static)函数的函数,这通常会(无需诊断)导致链接器错误。
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required. (C++11 3.2/3)
总结一下:
- 切勿在一个翻译单元中多次定义任何内容(这是一个 .cpp 文件,所有内容都直接或间接包含 headers)。
- 您可以将一定数量的东西放入 header 文件中,它们将在几个不同的翻译单元中被包含 一次,例如:
inline
函数class
类型和template
sstatic
个class template
的数据成员。
如果你有:
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; }
而你 link 将这些文件放在一个可执行文件中,你违反了 one-definition-rule
因为 inline
函数的两个版本不相同。