6

在 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 基类初始化是通过构造函数进行的,而不是聚合。

4

0 回答 0