检查两种类型是否可以别名

Qix*_*Qix 3 c++ type-traits

我有一个接受公共API函数(在库头)struct foo &,以及该函数的内部实现调用,需要一个第三方的依赖性的功能struct bar *

我不想将第三方依赖项引入公共头文件,因为库将以二进制形式分发,并且此依赖项是一个实现细节。

但是,我不打算附加任何附加信息foo,而是希望能够这样做reinterpret_cast<bar*>(&foo)以减少我必须执行的副本数量(这是一个非常频繁调用的函数)。

标准库是否有一个type_trait或其他一些机制来检查foo和的结构bar是否相同?我知道这将需要更多的维护保养,以确保标头也与内部依赖项的类型定义匹配,但这很好,因为它不太可能很快改变。

最终我需要类似的东西

struct foo {
    int a;
    const char *b;
};

struct bar {
    int c;
    const char *d;
};

static_assert(
    std::is_aliasable_to<foo, bar>::value, //        <-- Is this possible?
    "foo must be structurally equivalent to bar"
);

void public_api_function(foo &f) {
    private_third_party_function(
        reinterpret_cast<bar*>(&f)
    );
}
Run Code Online (Sandbox Code Playgroud)

Art*_*yer 5

reinterpret_cast<bar*>(&f) 由于严格别名,总是 UB。

如果没有严格别名,您可以使用 c++20's std::is_layout_compatible,但没有任何编译器支持。

你可以使用这样的黑客:

template<typename T, typename U>
constexpr bool is_same_member_type(T foo::*, U bar::*) {
    return std::is_same_v<T, U>;
}

#define HAS_SAME_MEMBER(foo_name, bar_name) (offsetof(foo, foo_name) == offsetof(bar, bar_name) && is_same_member_type(&foo:: foo_name, &bar:: bar_name))

// add more HAS_SAME_MEMBER calls if new members are added
static_assert(
    sizeof(foo) == sizeof(bar) &&
    std::is_standard_layout_v<foo> && std::is_standard_layout_v<bar> &&
    HAS_SAME_MEMBER(a, c) &&
    HAS_SAME_MEMBER(b, d),
    "foo must be structurally equivalent to bar"
);

#undef HAS_SAME_MEMBER
Run Code Online (Sandbox Code Playgroud)