在内联和constexpr功能的情况下,“服从ODR”是什么意思?

时间:2015-03-26 19:37:20

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

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

3 个答案:

答案 0 :(得分:3)

  

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

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

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的每个定义应由相同的令牌序列组成;和
  •   

答案 1 :(得分:3)

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

  

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

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

  

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

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

  

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

总结一下:

  • 永远不要在一个翻译单元中多次定义任何内容(这是一个.cpp文件以及所有直接或间接包含的标题)。
  • 您可以将一定数量的内容放入头文件中,其中一次包含在几个不同的翻译单元中,例如:
    • inline函数
    • class类型和template s
    • static class template
    • 的数据成员

答案 2 :(得分:1)

如果你有:

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