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

问题描述

鉴于 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'

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


第二个:

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

这里,this 指针本身不是一个常量表达式(我们不知道它指向什么),所以通过它访问任何东西都会失败。这是使用未知引用的常量表达式的更广泛案例的一部分,这种情况不会真正影响表达式的常量性(请参阅我在 constexpr array size problem 上的博客文章)。我最近写了一篇论文 on this topic,主要侧重于参考文献,但 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 不是静态成员很重要?

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


我建议使用 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()(只是因为它是 constevalthis 不在这里)

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


相关问题:

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...