Reputation: 15103
I have a public API function (in a library header) that accepts a struct foo &
, and that function's internal implementation calls a third-party dependency's function that requires a struct bar *
.
I do not want to pull in the third party dependency into the public header as the library will be distributed in binary form and this dependency is an implementation detail.
However, I do not intend to attach any additional information to foo
and instead want to be able to do reinterpret_cast<bar*>(&foo)
in order to reduce the amount of copies I have to perform (it's a very frequently called function).
Does the standard library have a type_trait
or some other mechanism to check if the structure of foo
and bar
are identical? I understand that this will require more maintanence upkeep on my end to make sure the header matches the internal dependency's type definition as well, but that's fine as it's unlikely to change any time soon.
Ultimately I need something like
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)
);
}
Upvotes: 4
Views: 133
Reputation: 40801
reinterpret_cast<bar*>(&f)
is always UB because of strict-aliasing.
Without strict-aliasing, you could use c++20's std::is_layout_compatible
, but there isn't any compiler support for that.
You could use a hack like this:
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
Upvotes: 6