如何获取非静态 std::array 成员的 constexpr `.size()`

How to obtain constexpr `.size()` of a non-static std::array member

鉴于 std::array<T,N>::size 是 constexpr,在下面的代码段中

清单:

// 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;
};

我建议首先“求助于”一个变量来定义大小:

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;
};

Why does it matter that Foo1::u is not a static member?

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


我建议使用 std::variant 而不是 union。使用起来更方便。

这些情况有点不同。

第一个:

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

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


第二个:

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

这里,this指针本身并不是常量表达式(我们不知道它指向什么),所以通过它访问任何东西都会失败。这是常量表达式使用未知引用的更广泛情况的一部分,其使用方式不会真正影响表达式的常量性(请参阅我的博客 post on the constexpr array size problem). I recently wrote a paper on this topic 主要关注参考文献,但 this 是其上的一个狭窄扩展。

不管怎样,目前这也行不通,因为一切都必须是常数。所以你必须按照你的建议求助于一些东西:单独公开你想要的常量。

可以直接从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(); }

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

invalid use of non-static data member 'Foo1::u'

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

'this' is not a constant expression*

意味着你不能调用this.length()(仅仅因为它是consteval但是this不在这里)

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


相关问题:

  • Why is constexpr not automatic?
  • Why isn't std::array::size static?