问题描述
鉴于 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()
(只是因为它是 consteval
但 this
不在这里)
为什么?因为这是标准所说的,否则根本没有理由使用 constexpr
说明符,因为编译器可以推断出它,不是吗?
相关问题: