![](/img/trans.png)
[英]Why do I need to member-initialize a non-static array member in a constexpr class?
[英]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.