请考虑以下类型定义:
struct lit
{
enum { A, B } value;
constexpr lit() : value(A) { }
constexpr lit(int) : value(B) { }
};
根据 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;
}
标准的第 9.4.2/3 节虽然没有直接说明,但暗示我不必为 static constexpr
成员指定定义,除非它们是 ODR 使用的(例如,考虑 foo::i
)。
当我用 clang 编译上面的代码时,它提示说我缺少 foo::a
和 foo::b
的定义,因为它认为它们是 odr-used .请参阅 coliru 上的示例.
另一方面,gcc 吞下它并愉快地打印出正确的结果。同样,这是关于 coliru 的示例.
所以,我的问题有两个方面:
foo::a
和foo::b
真的是 odr-used 吗?如果是,请解释它们与foo::i
的不同之处。需要对
lit
进行哪些更改以使其不需要foo::a
和foo 的类外定义: :b
?换句话说,我希望foo::a
和foo::b
的行为方式与foo::i
相同。
更新:
就 lit
被 odr 使用而言,Barry 的回答似乎是正确的。为了说明,如果我添加以下功能:
void bar(const int& x)
{
std::cout << "bar(" << x << ")" << std::endl;
}
和下面的主线:
bar(foo::i);
gcc 现在也提示了。
最佳答案
Are
foo::a
andfoo::b
really odr-used?
我相信答案是肯定的。我们正在复制构造 a
和 b
。 lit
有一个隐式复制构造函数,它是:
constexpr lit(lit const& rhs) = default;
也就是说,我们将 foo::a
和 foo::b
绑定(bind)到一个引用,这使它们成为 odr-used。这对 foo::i
来说不是问题,因为 int
不是类类型,因此没有复制构造函数。
我不确定你能做些什么来避免这种情况,除了不复制这两个文字而是复制枚举(即 auto a = foo::a.value;
不odr-use foo::a
).
关于c++ - 创建非 odr 使用的文字类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36434520/