Страницы

Поиск по вопросам

четверг, 16 мая 2019 г.

constexpt function with anonymous union in C++

Всем привет!
Сейчас у меня такой код:
// Source.hpp
/** * @brief Method that checks the endian type on the system. * @return DATA_LITTLE_ENDIAN(0x02) - if on the system little endian, otherwise - DATA_BIG_ENDIAN(0x01). */ static inline DATA_ENDIAN_TYPE CheckSystemEndian(void) noexcept { const union { const uint16_t value; const uint8_t data[sizeof(uint16_t)]; } endian { 0x0102 }; return static_cast(endian.data[0]); }
Class Foo { static const DATA_ENDIAN_TYPE system_endian; }
// Source.cpp inline const DATA_ENDIAN_TYPE BinaryDataEngine::system_endian = CheckSystemEndian();
Что требуется: Мне хочется решать эту задачу в compile-time, следовательно необходимо переделать функция CheckSystemEndian() на constexp. Однако в этой задаче мне очень мешает union
Ошибка следующая:
constexpr function never produces a constant expression. Read of member 'data' of union with active member 'value' is not allowed in a constant expression.
Подсткажите, пожалуйста, способ, как можно добиться требуемой функциональности в compile-time. Спасибо.


Ответ

Насколько я знаю, определить порядок байт (endianness) на этапе компиляции невозможно в принципе (стандартными средствами). Тут нужен reinterpret_cast, а он не считается constexpr выражением.
В С++20 для этого появится std::endian, и можно будет писать так:
#include
constexpr bool is_big_endian = std::endian::native == std::endian::big; constexpr bool is_little_endian = std::endian::native == std::endian::little;
Дожидаясь С++20, можно использовать нестандартные фичи компиляторов. Например, GCC умеет так:
constexpr bool is_big_endian = __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; constexpr bool is_little_endian = __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__;

Кроме того, у вас в программе неопределенное поведение, ведь С++, в отличие от С, не позволяет читать из неактивного поля union'а. Пруф.
Вот пример, как можно исправить код:
static inline DATA_ENDIAN_TYPE CheckSystemEndian(void) noexcept { const uint16_t value = 0x0102; return static_cast((uint8_t &)value); }
К тому же, так он еще и места меньше занимает.

Комментариев нет:

Отправить комментарий