是否有一种(可移植的)方法来检测 C++ 类 中的布局变化?

Is there a (portable) way to detect layout change in C++ classes?

例如,假设我有一个具有典型序列化模式的 class Foo。

struct Foo {
    int a;
    bool b;
    template <typename Archive>
    void serialize(Archive & ar) {
        ar & a;
        ar & b;
    }
};

现在假设有人过来添加了一个字段。

struct Foo {
    int a;
    bool b;
    std::string c;

    template <typename Archive>
    void serialize(Archive & ar) {
        ar & a;
        ar & b;
    }
};

这编译得很好,但存档方法是错误的。我可以添加类似

的内容

namespace detail {
template <int a, int b>
void AssertSizeOfImplementation() {
    static_assert(a == b, "Size does not match (check stack trace)");
}
}  
template <typename T, int size>
void AssertSizeOf() {
    detail::AssertSizeOfImplementation<sizeof(T), size>();
}


struct Foo {
    int a;
    bool b;

    template <typename Archive>
    void serialize(Archive& ar) {
        ar& a;
        ar& b;
        AssertSizeOf<Foo,8>();
    }
};

现在,如果我添加额外的字段,我将看到一个编译错误

: In instantiation of 'void detail::AssertSizeOfImplementation() [with int a = 40; int b = 8]':

然后我可以修复我的序列化代码并更新断言。

然而这不是很便携。 sizeof 将 return 不同的结果,具体取决于包装和体系结构。

除了使用 sizeof 之外,还有其他替代方法吗?

(在 Godbolt 上玩这个 https://godbolt.org/z/fMo8ETjnr

boost 中有很酷的库:boost pfr。我从未在实际项目中使用过它(只是一些玩具),但似乎工作得很好:

struct Foo {
    int a;
    bool b;

    template <typename Archive>
    void serialize(Archive& ar, const unsigned int)
    {
        boost::pfr::for_each_field(*this, [&ar](const auto& field) { ar& field; });
    }
};

Live demo.

现在,无需更改序列化代码即可考虑字段列表中的任何更改。

我试过 godbolt,但未能解决链接问题(找不到 boost 库),所以它实际上 运行。