检查两种类型是否可以别名
Check if two types can be aliased
我有一个 public API 函数(在库 header 中)接受 struct foo &
,并且该函数的内部实现调用 third-party需要 struct bar *
.
的依赖函数
我不想将第三方依赖项引入 public header,因为库将以二进制形式分发,并且此依赖项是一个实现细节。
但是,我不打算将任何附加信息附加到 foo
,而是希望能够执行 reinterpret_cast<bar*>(&foo)
以减少我必须执行的副本数量(这是一个经常被调用的函数)。
标准库是否有 type_trait
或其他机制来检查 foo
和 bar
的结构是否相同?我知道这将需要我进行更多维护以确保 header 也与内部依赖项的类型定义相匹配,但这很好,因为它不太可能很快改变。
最终我需要类似
的东西
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)
);
}
reinterpret_cast<bar*>(&f)
总是 UB 因为 strict-aliasing.
如果没有 strict-aliasing,您可以使用 c++20 的 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
我有一个 public API 函数(在库 header 中)接受 struct foo &
,并且该函数的内部实现调用 third-party需要 struct bar *
.
我不想将第三方依赖项引入 public header,因为库将以二进制形式分发,并且此依赖项是一个实现细节。
但是,我不打算将任何附加信息附加到 foo
,而是希望能够执行 reinterpret_cast<bar*>(&foo)
以减少我必须执行的副本数量(这是一个经常被调用的函数)。
标准库是否有 type_trait
或其他机制来检查 foo
和 bar
的结构是否相同?我知道这将需要我进行更多维护以确保 header 也与内部依赖项的类型定义相匹配,但这很好,因为它不太可能很快改变。
最终我需要类似
的东西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)
);
}
reinterpret_cast<bar*>(&f)
总是 UB 因为 strict-aliasing.
如果没有 strict-aliasing,您可以使用 c++20 的 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