【问题标题】:How to obtain constexpr `.size()` of a non-static std::array member如何获取非静态 std::array 成员的 constexpr `.size()`
【发布时间】:2021-02-07 18:00:25
【问题描述】:

鉴于std::array<T,N>::size 是 constexpr,在下面的 sn-p 中

  • 为什么Foo1::u 不是static 成员很重要?该类型在编译时是已知的,它的 size() 也是如此。
  • Foo2::bigger() 有什么问题?

上市:

// x86-64 gcc 10.1
// -O3 --std=c++20 -pedantic -Wall -Werror

#include <array>
#include <cstdint>

union MyUnion {
    std::array<uint8_t,32> bytes;
    std::array<uint32_t,8> words;
};

struct Foo1 {
    MyUnion u;
    static constexpr size_t length {u.bytes.size()};
        //invalid use of non-static data member 'Foo1::u'
};

struct Foo2 {
    MyUnion u;
    size_t x;
    consteval int8_t length() const { return u.bytes.size(); };
    bool bigger() const { return x > length(); }
        //'this' is not a constant expression
};

我想在 MyUnion 声明中保留 std::array 长度,而不是诉诸

constexpr size_t LEN {32};
union MyUnion {
    std::array<uint8_t,LEN> bytes;
    std::array<uint32_t,LEN/4> words;
};

【问题讨论】:

  • 请每个 stackoverflow.com 问题一个问题。这两个编译错误有不同的原因。
  • 顺便说一下,如果你初始化了bytes,你就不能使用words,因为它们没有共同的初始序列
  • 想象一个静态函数因为您更改了一个非静态类成员而中断。这不好。

标签: c++ constexpr c++20 stdarray


【解决方案1】:

这些情况有点不同。

在第一个:

    static constexpr size_t length {u.bytes.size()};
        //invalid use of non-static data member 'Foo1::u'

您正在尝试访问没有对象的非静态数据成员。那不是你能做的事情。需要有 some Foo1 与此表达式相关联。在非静态成员函数的上下文中,它会隐含为this-&gt;u,但那里仍然需要一些对象。只有一个例外:你可以写sizeof(Foo1::u)


第二个:

    consteval int8_t length() const { return u.bytes.size(); };

这里,this 指针本身并不是一个常量表达式(我们不知道它指向什么),所以通过它访问任何东西都会失败。这是使用未知引用的更广泛的常量表达式案例的一部分,这种方式不会真正影响表达式的常量性(请参阅我在constexpr array size problem 上的博客文章)。我最近写了一篇论文on this topic,主要关注参考文献,但this 是在此基础上的狭义延伸。

无论如何,现在这也行不通,因为一切都必须是常数。因此,您必须按照您的建议采取一些措施:分别公开您想要的常量。

【讨论】:

    【解决方案2】:

    我建议首先“诉诸”一个变量来定义大小:

    union MyUnion {
        static constexpr std::size_t size = 32;
    
        using byte = std::uint8_t;
        using word = std::uint32_t;
        
        std::array<byte, size> bytes;
        std::array<word, size / sizeof(word)> words;
    };
    
    struct Foo1 {
        using Union = MyUnion;
        Union u;
        static constexpr std::size_t length = Union::size;
    };
    

    为什么 Foo1::u 不是静态成员很重要?

    非静态成员只能在成员函数中访问。


    我建议使用std::variant 而不是union。它更容易使用。

    【讨论】:

      【解决方案3】:

      可以直接从type中获取

      // direct
      consteval static auto length() { return std::tuple_size<decltype(MyUnion::bytes)>::value; }
      // with indirection
      consteval static auto length() { return std::tuple_size<std::decay_t<decltype(u.bytes)>>::value; }
      

      或者你可以通过创建新实例来做到这一点。

      // direct
      consteval static auto length() { return MyUnion{.bytes={}}.bytes.size(); }
      // just the member + indirection
      consteval static auto length() { return decltype(u.bytes){}.size(); }
      

      对于您在代码中遇到的错误

      非静态数据成员'Foo1::u'的使用无效

      意味着您不能在没有实例的情况下使用非静态数据成员 u(例如在 static 成员函数内部)。

      'this' 不是常量表达式*

      意味着你不能打电话给this.length()(只是因为它是constevalthis不在这里)

      为什么?因为这是标准所说的,否则根本没有理由使用constexpr 说明符,因为编译器可以推断出来,不是吗?


      相关问题:

      【讨论】:

      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 2016-01-03
      • 2021-04-18
      • 2016-04-10
      • 1970-01-01
      • 2015-02-25
      • 2016-07-29
      相关资源
      最近更新 更多