C++ 创建非odr使用的文字类型 请考虑以下类型定义: struct lit { enum { A, B } value; constexpr lit() : value(A) { } constexpr lit(int) : value(B) { } };

C++ 创建非odr使用的文字类型 请考虑以下类型定义: struct lit { enum { A, B } value; constexpr lit() : value(A) { } constexpr lit(int) : value(B) { } };,c++,c++14,C++,C++14,根据C++14标准(3.9/10),此类型符合文字类型。接下来,请考虑以下使用场景: struct foo { static constexpr lit a { }; static constexpr lit b { 10 }; static constexpr int i { 42 }; }; int main() { lit a = foo::a; lit b = foo::b; int i = foo::i; std::cout

根据C++14标准(3.9/10),此类型符合文字类型。接下来,请考虑以下使用场景:

struct foo
{
    static constexpr lit a { };
    static constexpr lit b { 10 };
    static constexpr int i { 42 };
};

int main()
{
    lit a = foo::a;
    lit b = foo::b;
    int i = foo::i;

    std::cout << "a=" << a.value << std::endl;
    std::cout << "b=" << b.value << std::endl;
    std::cout << "i=" << i       << std::endl;
    return 0;
}
并将以下行连接到main:

bar(foo::i);
gcc现在也在抱怨

foo::a
foo::b
是否真的使用了odr

我相信答案是肯定的。我们正在复制构建
a
b
lit
有一个隐式复制构造函数,它是:

constexpr lit(lit const& rhs) = default;
也就是说,我们将
foo::a
foo::b
绑定到一个引用,这使得它们可以被odr使用。这对于
foo::i
来说不是问题,因为
int
不是类类型,因此没有复制构造函数


除了不复制两个文本,而是复制枚举(即
auto a=foo::a.value;
不使用
foo::a
)之外,我不确定您可以做些什么来避免这种情况。

但我认为这属于[basic.def.odr]中的一个例外/3因为
lit
有一个简单的复制构造函数,用于执行从左值到右值的转换。@巴里,谢谢你的回答,但是3.2/3呢。。。哦,是的,布赖恩就是这么说的above@Brian这是一个措辞非常笨拙的句子。它说左值到右值的转换不会调用任何非平凡函数?但不管怎样,我们在哪里转换成右值?@Brian(顺便说一句,并不是说你错了——我不确定是哪一种方式)我对[basic.def.odr]/3的这句话感到挠头:一个名为潜在计算表达式ex的变量x是ex使用的odr,除非将左值应用到右值转换(4.1)to x产生一个不调用任何非平凡函数的常量表达式(5.20),如果x是一个对象,ex是表达式e的潜在结果集的一个元素,其中左值到右值的转换(4.1)应用于e,或者e是一个丢弃的值表达式(第5条)。特别是斜体部分
constexpr lit(lit const& rhs) = default;