c++ - 创建非 odr 使用的文字类型

标签 c++ c++14

请考虑以下类型定义:

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::afoo::b 的定义,因为它认为它们是 odr-used .请参阅 coliru 上的示例.

另一方面,gcc 吞下它并愉快地打印出正确的结果。同样,这是关于 coliru 的示例.

所以,我的问题有两个方面:

  1. foo::afoo::b 真的是 odr-used 吗?如果是,请解释它们与 foo::i 的不同之处。

  2. 需要对 lit 进行哪些更改以使其不需要 foo::afoo 的类外定义: :b?换句话说,我希望 foo::afoo::b 的行为方式与 foo::i 相同。

更新:

lit 被 odr 使用而言,Barry 的回答似乎是正确的。为了说明,如果我添加以下功能:

void bar(const int& x)
{
    std::cout << "bar(" << x << ")" << std::endl;
}

和下面的主线:

bar(foo::i);

gcc 现在也提示了。

最佳答案

Are foo::a and foo::b really odr-used?

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

constexpr lit(lit const& rhs) = default;

也就是说,我们将 foo::afoo::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/

相关文章:

c++ - 避免返回的 const locals?

c++ - 为什么 make_optional 会衰减它的参数类型?

c++11:如何编写包装函数来生成 `std::function` 对象

c++ - 从 .cpp 文件 (C++) 中的头文件读取枚举

c++ - 我应该按值还是按右值引用捕获返回值?

c++ - Visual Studio 2008 中的非托管 C++ 单元测试

c++ - 类接口(interface)功能

c++ - 为什么 make_unique 不能与 unique_ptr::reset 一起使用?

C++ 简单线程启动问题

c++ - 评估宏中传递的参数