Учитывая некоторые структуры POD, подобные этому:
struct StandardHeader
{
uint32_t field1;
uint32_t field2;
};
struct TypeA
{
StandardHeader Header;
uint8_t field3;
};
struct TypeB
{
StandardHeader Header;
uint16_t field4;
};
Я хотел бы написать черту типа (или что-то подобное, что может в конечном итоге использоваться в static_assert
и std::enable_if
или иным образом отключить шаблонный метод), которое может обнаружить существование поля StandardHeader
в качестве первого член стандартного типа макета - т.е. такой, что reinterpret_cast<StandardHeader*>(&instance)
безопасен.
(По сути, проверка базового типа is-a , за исключением того, что типы должны быть POD, что не будет истинным, если я использую фактическое наследование C ++.)
Мне удалось написать что-то, что использовало идиому обнаружения, чтобы убедиться, что тип является стандартным макетом и имеет Header
член правильного типа:
template<typename, typename = std::void_t<>>
struct HasStandardHeader : std::false_type {};
template<typename T>
struct HasStandardHeader<T,
std::void_t<decltype(std::declval<T>().Header)>>
: std::conditional_t<
std::is_standard_layout_v<T> &&
std::is_same_v<decltype(std::declval<T>().Header), StandardHeader>
, std::true_type, std::false_type> {};
Вышесказанное частично работает, но не подтверждает, что поле было первым.
Я попытался добавить что-то вроде этого выражения, чтобы обнаружить это, но это не работает:
static_cast<uint8_t*>(&static_cast<T*>(0)->Header) - static_cast<uint8_t*>(0)) == 0
(Другие неудачные попытки связаны с вызовом метода constexpr bool
, но, к сожалению, они не действительны в conditional_t
. Или, по крайней мере, при использовании &
или чего-то еще.)
В идеале я бы предпочел что-то, что просто обнаруживает поле с правильным типом, там, даже не требуя, чтобы оно было названо Header
. Это возможно? И есть ли лучший способ переписать вышесказанное?
Как упоминалось ранее, конечная цель состоит в том, чтобы сделать этот метод:
template<typename T>
bool Process(T& data, size_t len);
либо исчезнет, либо static_assert
, если T
не относится к типу POD с правильным первым членом.
Редактировать : похоже, я немного усложнил это. Добавление этого выражения заставляет его работать как положено:
offsetof(T, Header) == 0
Но сейчас:
- Есть ли лучший способ написать все это?
- Можно ли написать это так, чтобы нам не требовалось, чтобы поле называлось
Header
?