请考虑以下类型定义:
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-used (例如,考虑foo::i
)。
当我用clang编译上面的内容时,它抱怨我错过了foo::a
和foo::b
的定义,因为它认为它们是使用过的。请参阅coliru上的示例。
所以,我的问题是双重的:
foo::a
和foo::b
真的有点用吗?如果是这样,请解释为什么以及它们与foo::i
的区别。
需要对lit
进行哪些更改才能使其不需要foo::a
和foo::b
的类外定义?换句话说,我希望foo::a
和foo::b
的行为方式与foo::i
相同。
更新:
似乎巴里的答案在lit
被使用的方面是正确的。为了说明,如果我添加以下功能:
void bar(const int& x)
{
std::cout << "bar(" << x << ")" << std::endl;
}
以及以下第一行:
bar(foo::i);
gcc现在也抱怨。
答案 0 :(得分:3)
foo::a
和foo::b
真的有用吗?
我相信答案是肯定的。我们正在复制构建a
和b
。 lit
有一个隐式的复制构造函数,它是:
constexpr lit(lit const& rhs) = default;
也就是说,我们将foo::a
和foo::b
绑定到引用,这使得它们使用起来很常见。这不是foo::i
的问题,因为int
不是类类型,因此没有复制构造函数。
我不知道你能做些什么来避免这种情况,除了不复制两个文字而是复制枚举(即auto a = foo::a.value;
不会使用foo::a
)。