繁体   English   中英

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

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

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

  • 为什么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;
};

这些情况有点不同。

在第一个:

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

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


在第二个中:

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

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

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

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

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 不是 static 成员很重要?

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


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

可以直接从 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() (只是因为它是consteval this不在这里)

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


相关问题:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM