【问题标题】:What means "obey ODR" in case of inline and constexpr function?在 inline 和 constexpr 函数的情况下,“服从 ODR”是什么意思?
【发布时间】:2015-05-30 23:52:29
【问题描述】:

我刚刚读到 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 呢?

【问题讨论】:

  • 这意味着您可以在不同的翻译单元中对它们进行多个定义。

标签: c++ c++11 inline constexpr one-definition-rule


【解决方案1】:

我刚刚读到 constexpr 和 inline 函数遵循单一定义规则,但它们的定义必须相同。

这是指不同翻译单元中的内联函数。在您的示例中,它们都在同一个翻译单元中。

这在draft C++ standard 3.2 一个定义规则[basic.def.odr] 中涵盖:

类类型(第 9 条)、枚举类型(7.2)、内联函数可以有多个定义 外部链接(7.1.2),类模板(第14条),非静态函数模板(14.5.6),静态数据成员 类模板 (14.5.1.3) 的成员函数、类模板的成员函数 (14.5.1.1) 或模板特化 在程序中未指定某些模板参数(14.7、14.5.5),前提是每个定义 出现在不同的翻译单元中,并且只要定义满足以下要求。给定 这样一个名为 D 的实体定义在多个翻译单元中,那么

并包括以下项目符号:

  • D 的每个定义都应由相同的标记序列组成;和

【讨论】:

  • 很好的解释。
【解决方案2】:

您在一个翻译单元中重复定义函数。这总是被禁止的:

任何翻译单元都不得包含一个以上的任何变量、函数、类类型、枚举的定义 类型或模板。 (C++11 3.2/1)

对于inline 函数,您可以在多个翻译单元中以完全相同的方式定义相同的函数(读取:.cpp 文件)。事实上,您必须在每个翻译单元中定义它(通常通过在头文件中定义它来完成):

一个内联函数应该在使用它的每个翻译单元中定义。 (C++11 3.2/3)

对于具有外部链接(非静态)函数的“正常”(非内联、非 constexpr、非模板等)函数,这通常会(无需诊断)导致链接器错误。

每个程序都应该包含一个对每个非内联函数或 odr 使用的变量的定义 在该计划中;无需诊断。 (C++11 3.2/3)

总结一下:

  • 切勿在一个翻译单元(即 .cpp 文件和所有直接或间接包含的标头)中多次定义任何内容。
  • 您可以将一定数量的内容放入头文件中,它们将被包含在几个不同的翻译单元中一次,例如:
    • inline函数
    • class 类型和templates
    • static class template 的数据成员。

【讨论】:

  • 很好的解释。
【解决方案3】:

如果你有:

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 函数的两个版本不同。

【讨论】:

  • 很好的解释。
猜你喜欢
  • 2013-11-06
  • 1970-01-01
  • 2020-04-04
  • 2017-03-28
  • 2016-08-26
  • 2012-04-21
  • 2014-10-27
  • 2019-10-15
  • 2020-11-03
相关资源
最近更新 更多