不幸的是,我constexpr
对头文件中声明的全局常量和odr感到困惑。
简而言之:我们可以从这里得出结论吗
https://isocpp.org/files/papers/n4147.pdf
那
constexpr MyClass const MyClassObj () { return MyClass {}; }
constexpr char const * Hello () { return "Hello"; }
优于
constexpr MyClass const kMyClassObj = MyClass {};
constexpr char const * kHello = "Hello";
如果要“仅使用”那些全局声明/定义的实体,又不想考虑如何使用它们,则可以在头文件中定义全局变量?
注意:从C ++ 17开始,您可以将变量声明为inline。
TL; DR:如果希望(非常)安全,请使用constexpr函数。但是,这并不是固有的必要,如果您对这些对象执行琐碎的操作并且仅对它们的值感兴趣,或者根本不在下面列出的危险情况下使用它们,则肯定不是必需的。
根本的问题是,const
名称空间范围内的变量(例如您的变量)通常具有内部链接([basic.link] /(3.2))。这意味着编译对应头的每个翻译单元将观察到不同的实体(即符号)。
现在想象一下,使用这些对象的标头中有一个模板或内联函数。ODR在这种情况下非常精确- [basic.def.odr] / 6:
因为我们在说,所以肯定会遇到“用常量表达式初始化”constexpr
。所以是“的对象具有在所有定义相同的值D
”有关,如果你没有猴子。
“对象不被滥用”可能是唯一可疑的条件。基本上,它要求您不必将变量运行时作为符号存在,这反过来意味着
您不会将其绑定到引用(=>您不会转发它!)
您不(既不明确也不隐含)获取其地址。
第二个规则的唯一例外是数组,只要产生的glvalue不违反以上两个规则,就可以将其作为下标操作中的隐式地址。
更确切地说,odr的使用由[basic.def.odr] / 3决定:
一种可变
x
其名称显示为潜在评估表达ex
是ODR-使用ex
,除非将所述左值到右值转换(4.1),以x
产率即不调用任何非平凡函数和一个常量表达式(5.20),如果x
是objectex
是表达式的一组潜在结果的元素e
,其中将lvalue-r -value转换(4.1)应用于e
,或者e
是舍弃值表达式(第5章)。
将ltr应用于任何constexpr
变量将按照第一部分的要求进行操作。第二部分要求将变量用作值而非实际对象; 也就是说,根据上述经验法则,最终将其丢弃或直接评估。
如果您避免在内联函数,模板等内部使用odr,则可以。但是,如果您使用相应constexpr函数的返回值,则不必担心,因为prvalue已经表现得更像值/文字(不是对象),并且constexpr函数是内联的,并且绝对不会违反ODR(如果您不要constexpr
在其中使用变量!)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句