Всем привет!
Сейчас у меня такой код:
// 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<DATA_ENDIAN_TYPE>(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 <type_traits>
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<DATA_ENDIAN_TYPE>((uint8_t &)value);
}
К тому же, так он еще и места меньше занимает.
Есть вариант а ля cmake или Lisp, мне больше нравится Лисп.
Makefile :
...
clean:
...TAB... @rm endian.hpp endian ...
endian.hpp: endian.cpp
...TAB... @g++ --std=c++11 endian.cpp -o endian
...TAB... @./endian > endian.hpp
...
endian.cpp :
# include <iostream>
volatile uint16_t const v16 { 0x0102 } ;
volatile uint8_t const * pv8 { reinterpret_cast < volatile uint8_t const * > ( & v16 ) } ;
bool const little_endian { ( * pv8 ) == 0x02 } ;
bool const big_endian { ( * pv8 ) == 0x01 } ;
int main ( ) {
if(little_endian) std::cout<<"# define MY_LITTLE_ENDIAN "<<std::endl;
else std::cout<<"# define MY_BIG_ENDIAN "<<std::endl;
std::cout<<"bool constexpr little_endian { "<<(little_endian ? "true" : "false")<<" } ;"<<std::endl;
std::cout<<"bool constexpr big_endian { "<<(big_endian ? "true" : "false")<<" } ;"<<std::endl; }
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
макс элемент нашел, а как переприсвоить не знаю
//Из текстового файла вводится символьная строка, состоящая из чисел, //разделенных пробеломСоставить программу, которая вводит строку, организует...
Нужно с использованием библиотеки yamlh написать код для сравнения yaml файлов