如何在其聚合初始化程序中使用类静态对象的大小?

Jac*_*ker 5 c++ sizeof static-variables aggregate-initialization

在Win32标准库中,使结构的第一个成员成为结构的大小是一个相当普遍的习惯用法,如下所示:

#include <cstddef>

struct wrapped_float
{
    std::size_t value; //Initialize with sizeof(wrapped_float)
    float other; //Actual info
};
Run Code Online (Sandbox Code Playgroud)

如果我创建一个全局对象,那么有一个简单的初始化语法可以自动适应以下类型的更改a

constexpr wrapped_float const a{ sizeof(a), 0 }; //OK
Run Code Online (Sandbox Code Playgroud)

我希望我的对象不是结构的静态成员,而不是创建全局对象:

struct test1 {
    static constexpr wrapped_float const b{ sizeof(b), 0 }; //Error!
};
Run Code Online (Sandbox Code Playgroud)

但是MSVC在此类代码上出错,抱怨b不是的成员struct test1。因此,我有两个相关的问题:

1.为什么全局成员和静态成员之间有区别?
2.有解决方法吗?

有问题的类型来自Win32标头,因此我无法从中添加或删除成员wrapped_float。(如果有用,我可以使用派生的类/结构。)

的明显变化

struct test2 {
    static constexpr wrapped_float const b{ sizeof(test::b), 0 };
};
Run Code Online (Sandbox Code Playgroud)

struct test3 {
    static constexpr wrapped_float const b{ sizeof(decltype(b)), 0 };
};
Run Code Online (Sandbox Code Playgroud)

产生相同的结果。我已经在Godbolt上进行了验证,该现象也不取决于我是否使用MSVC进行编译,唯一适用于x86-64 Clang的编译器。要得出M(非)WE,请写

int main() {
    return a.value + test1::b.value + test2::b.value + test3::b.value;
}
Run Code Online (Sandbox Code Playgroud)

编辑,19年7月26日下午3:10:问题(1)仍未解决。 这个问题表明,constexpr变量不大小,但这个广场不与事实sizeof(a) 确实编译。

为了后代的缘故,我将总结到目前为止评论中提到的一些解决方法。

保罗·桑德斯(Paul Sanders)指出,如果可以保证类型名称不会更改,则可以编写

struct test4 {
    static constexpr wrapped_float const b{ sizeof(wrapped_float), 0 };
};
Run Code Online (Sandbox Code Playgroud)

如果您想减少对的显式引用的数量wrapped_float,那么NRVO可以进行以下工作,

template<typename retval_t, typename...Args>
constexpr retval_t make(Args &&... args)
{
    return {sizeof(retval_t), std::forward<Args>(args)...};
}
Run Code Online (Sandbox Code Playgroud)

对应的构造器版本

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>...) {}
}
Run Code Online (Sandbox Code Playgroud)

在C ++ 20之前,b / c基类的初始化是通过构造函数进行的,而不是聚合的,起作用。