Min*_*ine 3 c++ one-definition-rule c++14
给出以下代码,是否使用Foo::FOO1ODR?
#include <iostream>
#include <map>
#include <string>
class Foo
{
public:
static constexpr auto FOO1 = "foo1";
void bar();
};
void Foo::bar()
{
const std::map<std::string, int> m = {
{FOO1, 1},
};
for (auto i : m)
{
std::cout << i.first << " " << i.second << std::endl;
}
}
int main()
{
Foo f;
f.bar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用-O1或以上编译代码,没关系,但如果编译-O0,我得到以下错误(请参阅coliru示例:
undefined reference to `Foo::FOO1'
Run Code Online (Sandbox Code Playgroud)
表示它是ODR使用的.这是什么?
我知道上面的代码是用-O构建的,但是在一个真实的(更复杂的)情况下:
undefined reference错误LinkTimeOptimization(-O2 -flto)所以它表明优化(-O)和LinkTimeOptimization(-flto)都会影响ODR使用规则?这在C++ 14和C++ 17之间是否有变化?
一种可变
x为潜在评估表达式出现的名字ex被ODR使用的由ex除非施加左值到右值转换到x产率的常量表达式不调用任何非平凡函数,并且如果x是一个对象,ex是的一个元素表达式的潜在结果集e,其中应用了左值到右值的转换([conv.lval])e,或者e是丢弃值表达式([expr.prop]).
第一部分是明显满足(FOO1被constexpr所以左值到右值转换确实产生恒定表达,而不必调用非平凡函数),但是在第二?
我们正在构建一个map.那里的相关构造函数需要一个initializer_list<value_type>,也就是说initializer_list<pair<const string, int>>.pair有一堆构造函数,但在这里调用的是:
template <class U1, class U2>
constexpr pair(U1&& x, U2&& y); // with U1 = char const*&, U2 = int
Run Code Online (Sandbox Code Playgroud)
这里的重要部分是我们不是直接构造一个string,我们正在经历这个转换构造函数pair,它涉及绑定一个引用FOO1.这是一种奇怪的用法.这里没有左值到右值的转换,也不是丢弃值表达式.
基本上,当你拿一些东西的地址,这是一种使用 - 它必须有一个定义.所以你必须添加一个定义:
constexpr char const* Foo::FOO1;
Run Code Online (Sandbox Code Playgroud)
另请注意,这个:
std::string s = FOO1;
Run Code Online (Sandbox Code Playgroud)
会不会是一个ODR使用.这里我们直接调用一个带char const*参数的构造函数,这个参数是一个左值到右值的转换.
在C++ 17中,我们在[dcl.constexpr]中得到了这个新句子:
使用constexpr说明符声明的函数或静态数据成员隐式地是内联函数或变量([dcl.inline]).
这并没有改变任何关于odr-use的东西,FOO1在你的程序中仍然使用了odr.但它确实FOO1隐式地生成内联变量,因此您不必为其明确添加定义.很酷.
另请注意,仅仅因为程序编译和链接并不意味着缺少定义的变量不会被使用.
所以它表明优化(-O)和LinkTimeOptimization(-flto)都会影响ODR使用规则?
他们不.优化很酷.
| 归档时间: |
|
| 查看次数: |
212 次 |
| 最近记录: |