在 Win32 标准库中,使结构的第一个成员成为结构的大小是相当常见的习惯用法,如下所示:
#include <cstddef>
struct wrapped_float
{
std::size_t value; //Initialize with sizeof(wrapped_float)
float other; //Actual info
};
如果我创建一个全局对象,那么有一个简单的初始化语法可以自动适应类型的变化a
:
constexpr wrapped_float const a{ sizeof(a), 0 }; //OK
我不想创建一个全局对象,而是希望我的对象成为结构的静态成员:
struct test1 {
static constexpr wrapped_float const b{ sizeof(b), 0 }; //Error!
};
但此类代码的 MSVC 错误,抱怨b
不是struct test1
. 因此,我有两个相关的问题:
1. 为什么全局成员和类静态成员有区别?
2. 有解决办法吗?
有问题的类型来自 Win32 标头,因此我无法从wrapped_float
. (如果有用的话,我可以使用派生类/结构。)
的明显变化
struct test2 {
static constexpr wrapped_float const b{ sizeof(test::b), 0 };
};
和
struct test3 {
static constexpr wrapped_float const b{ sizeof(decltype(b)), 0 };
};
产生相同的结果。我已经在Godbolt上验证了这种现象并不取决于我使用 MSVC 编译的事实——唯一适用的编译器是 x86-64 Clang。总结一个 M(non-)WE,写
int main() {
return a.value + test1::b.value + test2::b.value + test3::b.value;
}
编辑,2019 年 7 月 26 日下午 3:10:问题 (1) 仍然悬而未决。 这个问题表明constexpr
变量没有大小,但这与编译 的事实sizeof(a)
不符。
为了后代,我将总结到目前为止评论中提到的一些解决方法。
Paul Sanders 指出,如果你能保证你的类型名称不会改变,那么你可以写
struct test4 {
static constexpr wrapped_float const b{ sizeof(wrapped_float), 0 };
};
如果您想减少对 的显式引用的数量wrapped_float
,那么 NRVO 的以下作品,
template<typename retval_t, typename...Args>
constexpr retval_t make(Args &&... args)
{
return {sizeof(retval_t), std::forward<Args>(args)...};
}
对应的构造函数版本
template<typename obj_ty>
struct auto_size : public obj_ty
{
public:
template<typename...Args>
auto_size(Args &&...args) : obj_ty(sizeof(retval_t), std::forward<Args>...) {}
}
直到 C++20 才起作用,b/c 基类初始化是通过构造函数进行的,而不是聚合。