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

社会主义新天地 提交于 2021-02-11 12:41:55

问题


Given that std::array<T,N>::size is constexpr, in the snippet below

  • Why does it matter that Foo1::u is not a static member? The type is known at compile time and so is its size().
  • What's wrong with Foo2::bigger()?

Listing:

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

I would like to keep std::array length in MyUnion declaration and not resort to

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

回答1:


These situations are a bit different.

In the first one:

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

You're trying to access a non-static data member without an object. That's just not a thing you can do. There needs to be some Foo1 associated with this expression. In the context of a non-static member function, it'd implicitly be this->u, but there still needs to be some object there. There's only one exception: you're allowed to write sizeof(Foo1::u).


In the second one:

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

Here, the this pointer is not itself a constant expression (we don't know what it points to), so accessing anything through it fails. This is part of a broader case of constant expressions using unknown references in a way that doesn't really affect the constant-ness of the expression (see my blog post on the constexpr array size problem). I recently wrote a paper on this topic which was focused primarily on references, but this is a narrow extension on top of that.

Either way, for now this can't work either, because everything has to be a constant. So you'll have to resort to something along the lines of what you suggest: expose the constant you want separately.




回答2:


I recommend "resorting to" a variable to define the size in the first place:

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?

Non-static members can be accessed only within member functions.


I recommend using std::variant instead of union. It's much easier to use.




回答3:


You can directly get it from 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; }

Or you can do it by create new instance.

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

For the errors you got in your code

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

means you cannot use non-static data member u without instance (e.g. inside static member function).

'this' is not a constant expression*

means you cannot call this.length() (simply because it's consteval but this is not here)

Why? because it's what the standard say, otherwise there is no reason to use constexpr specifier at all because compiler can infer it, isn't it?


Related question:

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


来源:https://stackoverflow.com/questions/66091284/how-to-obtain-constexpr-size-of-a-non-static-stdarray-member

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!