2016-06-25 3 views
10

Скажем, у нас есть реализация std::aligned_storage. Я определил два макроса для операторов alignof и alignas.Слишком много аргументов для функционального вызова макросов

#include <iostream> 
#include <cstddef> 

#define ALIGNOF(x) alignof(x) 
#define ALIGNAS(x) alignas(x) 

template<std::size_t N, std::size_t Al = ALIGNOF(std::max_align_t)> 
struct aligned_storage 
{ 
    struct type { 
     ALIGNAS(Al) unsigned char data[N]; 
    }; 
}; 

int main() 
{ 
    // first case 
    std::cout << ALIGNOF(aligned_storage<16>::type); // Works fine 

    // second case 
    std::cout << ALIGNOF(aligned_storage<16, 16>::type); // compiler error 
} 

Во втором случае я получаю ошибку в названии вопроса (составитель с Clang, подобной ошибкой с GCC). Ошибка, если я заменил макросы alignof и alignas соответственно. Почему это?

Перед тем, как начать спрашивать меня, почему я делаю это - оригинальные макросы имеют 98 совместимый код C++, такие как __alignof и __attribute__((__aligned__(x))) и те компилятор конкретные, поэтому макросы мой единственный выбор ...

EDIT: Так что в соответствии с вопросом, обозначенным как дубликат, дополнительный набор скобок исправит проблему.

std::cout << ALIGNOF((aligned_storage<16, 16>::type)); // compiler error 

Это не так. Итак, как я могу это сделать? (Удовлетворительный вопрос?)

+1

@melpomene, Это действительно не дает возможности решить проблему – chris

+1

Почему? Потому что запятая. - Расширение макросов видит запятую, прежде чем делать синтаксический смысл любого другого контента. –

+0

http://stackoverflow.com/questions/679979/how-to-make-a-variadic-macro-variable-number-of-arguments может быть полезным –

ответ

13

Препроцессор C/C++ не знает каких-либо конструкций языка C/C++, это просто препроцессор текста с его собственным синтаксисом и правилами. В соответствии с этим синтаксисом следующий код ALIGNOF(aligned_storage<16, 16>::type) является вызовом макроса ALIGNOF с двумя аргументами (aligned_storage<16 и 16>::type), поскольку в круглых скобках есть запятая.

Я предлагаю вам typedefaligned_storage<16, 16> и использовать этот тип внутри этого макроса.

+0

@melpomene Спасибо за редактирование, я не знал ** ** не работает внутри '' :) и моя реакция была медленнее, чем ваша :) – mvidelgauz

8

Как было объяснено, макро аргументы разделяются запятыми, которые не входят в дополнительные круглые скобки. Есть несколько простых иш способов обойти это, некоторые более общие, чем другие:

  1. Используйте VARIADIC макрос (или соответствующее расширение компилятора для C++ 98) (live example):

    #define ALIGNOF(...) alignof(__VA_ARGS__) 
    ALIGNOF(aligned_storage<16, 16>::type) 
    
  2. Получить звонящему передать количество аргументов и обернуть аргументы в дополнительных скобках (live example):

    #define ALIGNOF(n, tuple) alignof(BOOST_PP_TUPLE_ENUM(n, tuple)) 
    ALIGNOF(2 (aligned_storage<16, 16>::type)) 
    
  3. Получить са Мюллер перейти в «последовательности» (live example):

    #define ALIGNOF(seq) alignof(BOOST_PP_SEQ_ENUM(seq)) 
    ALIGNOF((aligned_storage<16)(16>::type)) 
    
  4. Если аргумент типа, используйте typedef (live example):

    typedef aligned_storage<16, 16>::type storage_t; 
    ALIGNOF(storage_t) 
    

    Обратите внимание, что шаблонных псевдонимы могут быть созданы до C++ 11 с помощью шаблонов, на структуру и подвергая type элемент:

    template<int N> 
    struct alias { 
        typedef typename aligned_storage<N, N>::type type; 
    }; 
    
  5. Если аргумент можно использовать в скобках, заставить вызывающего объекта обернуть аргумент в круглые скобки и использовать его напрямую. Это не относится к alignof.

Смежные вопросы