Замена этого макроса - PullRequest
       8

Замена этого макроса

2 голосов
/ 07 апреля 2011

Учитывая этот макрос

#define MAKE_TYPE(_a, _b, _c, _d) ((_a) | ((_b) << 8) | ((_c) << 16) | ((_d) << 24))

Я бы хотел заменить его так, чтобы вместо него использовался массив [4] . Так что я могу написать MAKE_TYPE ("ABCD") вместо уродливого MAKE_TYPE ('A', 'B', 'C', 'D')

Я использую это во время компиляции для генерации некоторых констант.

Но мне не нравится, когда я передаю такую ​​строку

#define MAKE_TYPE(s) ((s[3]) | ((s[2]) << 8) | ((s[1]) << 16) | ((s[0]) << 24))

ошибка: ссылка на массив не может появляться в константном выражении

Ну, это не сработало. Так что я подумал, что смогу разобраться с этим, используя шаблонное метапрограммирование

template< char[4] s > class MAKE_TYPE
{
 public:
 enum{ RESULT = s[3] | (s[2] << 8) | (s[1] << 16) | (s[0] << 24) };
};

К сожалению, это тоже не сработало. Я не могу поставить char [4] в шаблон. И я получаю эти ошибки:

ошибка: ожидается ">" до "s" ошибка: «s» не было объявлено в этой области ошибка: ссылка на массив не может появляться в константном выражении

Как я могу это сделать?

Ответы [ 5 ]

2 голосов
/ 07 апреля 2011

Вы пробовали еще несколько скобок и / или приведений?

#define MAKE_TYPE(s) (int((s)[3]) | (int((s)[2]) << 8) | (int((s)[1]) << 16) | (int((s)[0]) << 24))

Это работает для меня, я использую что-то очень похожее для кодов FourCC, и мой макрос используется множеством различных компиляторов.

2 голосов
/ 07 апреля 2011

Сообщение об ошибке означает, что оно говорит: массивы не могут появляться в константных выражениях.

Выражения шаблона должны быть выражениями констант, поэтому массивы не могут быть в аргументах шаблона.

Вы можете иметь указатель на массив, но это не то, что вам нужно.

Ах, учитывая, что ограничение составляет всего четыре символа, вы можете использовать многосимвольную константу, например 'ABCD' в одиночномцитаты.Но тогда порядок символов определяется реализацией.

Другая вещь, которую вы пытаетесь сделать, - это сгенерировать имя самого класса из символьных констант.Это возможно, если в макрос передать пустые буквы, а не символьные литералы, но на самом деле это не так.Даже если бы это сработало, это было бы довольно адски.

0 голосов
/ 07 апреля 2011

Как насчет этого?

template <typename T>
typename boost::enable_if_c<(T('1234')==0x31323334), T>::type
make(T v)
{
    return v;
}

const int value = make('ABCD');

Это защитная сеть для зависимого от компилятора поведения многосимвольной константы. Вы можете добавить дополнительные реализации для другого поведения компилятора, переключая байты по мере необходимости. Предполагается, что порядок следования байтов '1234' согласован для каждого компилятора.

Эксперты по шаблонам могут уточнить.

0 голосов
/ 07 апреля 2011

Вы можете использовать многосимвольную константу, например, int four = 'four'. Однако поведение зависит от компилятора.

0 голосов
/ 07 апреля 2011

Если вы знаете, что ввод char *:

template <class RT> RT MakeType( const char * _arg )
{
  return _arg[3] | (_arg[2] << 8) | (_arg[1] << 16) | (_arg[0] << 24);
}

еще:

template <class T, class RT> RT MakeType( const T &B0, const T &B1, const T &B2, const T &B3 )
{
  return B3 | (B2 << 8) | (B1 << 16) | (B0 << 24);
}

Я бы сделал:

inline unsigned int MakeType( const char * _arg )
{
  return _arg[3] | (_arg[2] << 8) | (_arg[1] << 16) | (_arg[0] << 24);
}

и заклинание, если это необходимо.

...