对于内联函数和 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 类型和 templates
    • staticclass 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 函数的两个版本不相同。