【问题标题】:array of class element as a static constexpr member类元素数组作为静态 constexpr 成员
【发布时间】:2014-04-06 08:47:54
【问题描述】:

我有一个关于类 Bar 的 constexpr 静态成员的引导问题 这是Bar 本身的数组。考虑以下完全正确的代码:

struct Foo {
  int i;
  static const std::array<Foo, 2> A;
};
const std::array<Foo, 2> Foo::A {{{1},{2}}};

现在我想要 Foo::A 不仅是 const,还有 constexpr。我面临 必须完成静态 constexpr 成员初始化的问题 类声明中。但是,由于声明尚未完成, 编译器还不知道实例的大小,因此拒绝 制作数组。例如

 struct Bar {
   int i;
   constexpr static const std::array<Bar, 2> A{{{1},{2}}};
 };

被拒绝

/usr/include/c++/4.8/array: In instantiation of ‘struct std::array<Bar, 2ul>’:
ess.cpp:14:56:   required from here
/usr/include/c++/4.8/array:97:56: error: ‘std::array<_Tp, _Nm>::_M_elems’ has incomplete type
       typename _AT_Type::_Type                         _M_elems;

有没有办法解决这个问题?还是一种解决方法?

【问题讨论】:

    标签: c++ arrays class c++11 constexpr


    【解决方案1】:

    目前这是不可能的,编译器无法提前知道 constexpr 是否实际允许/可能。将成员 A 替换为函数,它应该可以工作:

    struct Bar
    {
        int i;
        constexpr static std::array<Bar, 2> get_A()
        {
            return {{{1}, {2}}};
        }
    };
    

    相关(几乎重复):static constexpr member of same type as class being defined

    【讨论】:

    • 感谢指针确实非常接近我的问题。我对您的解决方案有疑问:它是否确保数组确实在编译时计算并且只存储一次?这里的目标是拥有某种多单例类,其中所有内容都是静态计算的。
    • 它应该做你要求的,但恐怕我目前没有办法证明它。我的编译器还不支持constexpr,而且很难验证,因为您不能向 constexpr-Constructors 添加任何信息语句或使用地址进行技巧。然而,即使编译器创建了多个实例,它也不应该影响运行时性能。并且结果数组应该是相同的,因为它是在编译时计算的。
    • 其实并没有解决问题。我真的很想有一个独特的数组来确保引用常量。如果我执行static_assert(&amp;Bar::get_A() == &amp;Bar::get_A(), "Duplicate"); 然后我收到警告Bar::get_A() 返回一个临时数组并且断言失败。
    • 当然它返回一个临时的,但是临时的构造在编译期间已经完成。编译器不会让您获取临时地址,这就是我所说的“难以验证”的意思。如果它不能解决您的问题,我很抱歉。如果您使用常规的 const 静态对象但使用常量表达式对其进行初始化怎么办?也许我遗漏了一些东西,但对我来说这样做并没有太大的好处。
    【解决方案2】:

    我找到了以下解决方案,可以确保

    1. 数组在编译时计算
    2. 数组存储在结构中而不被复制。

    这个想法是在 constexpr 数组上使用 const 引用。

    struct Bar {
      int i;
      static const std::array<Bar, 2> &A;
    };
    
    constexpr const std::array<Bar, 2> BarA {{{1},{2}}};
    const std::array<Bar, 2> &Bar::A = BarA;
    

    【讨论】:

      【解决方案3】:

      解决方案实际上只是在定义中只包含constexpr关键字,但声明中:

      struct Foo {
        int i;
        static const std::array<Foo, 2> A;
      };
      constexpr std::array<Foo, 2> Foo::A {{{1},{2}}};
      

      这确保Foo::A 被定义为一个实际的常量表达式。

      Live Demo

      this answer 归功于 Richard Smith。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-15
        • 2019-07-05
        • 2020-08-26
        • 2017-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多