Digamos que temos uma macro como esta
#define FOO(type,name) type name
Que poderíamos usar como
FOO(int, int_var);
Mas nem sempre tão simplesmente:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Claro que poderíamos fazer:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
o que não é muito ergonômico. As incompatibilidades do tipo Plus devem ser tratadas. Alguma ideia de como resolver isso com macro?
c++
c
macros
c-preprocessor
PoP
fonte
fonte
Respostas:
Porque colchetes também pode representar (ou ocorrem em) os operadores de comparação
<
,>
,<=
e>=
, a expansão macro não pode ignorar vírgulas dentro de colchetes como ele faz entre parênteses. (Isso também é um problema para colchetes e colchetes, embora eles geralmente ocorram como pares equilibrados.) Você pode colocar o argumento da macro entre parênteses:O problema é então que o parâmetro permanece entre parênteses dentro da expansão da macro, o que impede que seja lido como um tipo na maioria dos contextos.
Um bom truque para contornar isso é que em C ++, você pode extrair um nome de tipo de um nome de tipo entre parênteses usando um tipo de função:
Como a formação de tipos de função ignora parênteses extras, você pode usar esta macro com ou sem parênteses, onde o nome do tipo não inclui uma vírgula:
Em C, é claro, isso não é necessário porque os nomes dos tipos não podem conter vírgulas fora dos parênteses. Portanto, para uma macro de linguagem cruzada, você pode escrever:
fonte
template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}
Se eu aplicar esta solução aqui, as estruturas por trás da macro se tornam tipos dependentes e o prefixo do nome de tipo agora é necessário no tipo. Você pode adicioná-lo, mas a dedução de tipo foi quebrada, então agora você tem que listar manualmente os argumentos de tipo para chamar a função. Acabei usando o método do temple de definir uma macro para a vírgula. Pode não parecer tão bonito, mas funcionou perfeitamente.[]
e{}
, não são, só funciona com()
tristeza. Veja: No entanto, não há necessidade de colchetes ou colchetes para equilibrar ...#define PROTECT(...) argument_type<void(__VA_ARGS__)>::type
. Passar argumentos agora é facilmente possível, mesmo por meio de várias macros e, para tipos simples, você pode omitir PROTECT. No entanto, os tipos de função tornam-se ponteiros de função quando avaliados desta formaSe você não pode usar parênteses e não gosta da solução SINGLE_ARG de Mike, basta definir uma COMMA:
Isso também ajuda se você deseja sequenciar alguns dos argumentos da macro, como em
que imprime
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.fonte
#define STRVX(...) STRV(__VA_ARGS__)
e#define STRV(...) # __VA_ARGS__
,std::cout << STRV(type<A COMMA B>) << std::endl;
imprimirátype<A COMMA B>
estd::cout << STRVX(type<A COMMA B>) << std::endl;
imprimirátype<A , B>
. (STRV
é para "stringify variadic" eSTRVX
é para "stringify variadic expandida".)COMMA
macro em primeiro lugar. Foi com isso que eu terminei.Se o seu pré-processador for compatível com macros variadas:
Caso contrário, é um pouco mais tedioso:
fonte
Basta definir
FOO
comoEm seguida, invoque-o sempre com parênteses em torno do argumento de tipo, por exemplo
É claro que pode ser uma boa ideia exemplificar as invocações em um comentário sobre a definição da macro.
fonte
UNPACK
fazer quando usado assim) UNPACK type name
? Por quetype
obtém o tipo corretamente quando usado) UNPACK type name
? O que diabos está acontecendo aqui?Existem pelo menos duas maneiras de fazer isso. Primeiro, você pode definir uma macro que leva vários argumentos:
se você fizer isso, poderá acabar definindo mais macros para lidar com mais argumentos.
Em segundo lugar, você pode colocar parênteses em torno do argumento:
se você fizer isso, poderá descobrir que os parênteses extras bagunçam a sintaxe do resultado.
fonte
Isso é possível com P99 :
O código acima remove efetivamente apenas a última vírgula da lista de argumentos. Verifique com
clang -E
(P99 requer um compilador C99).fonte
A resposta simples é que você não pode. Este é um efeito colateral da escolha de
<...>
argumentos de modelo; o<
e>
também aparecem em contextos desequilibrados, de forma que o mecanismo da macro não pode ser estendido para tratá-los como faz com os parênteses. (Alguns dos membros do comitê defenderam um token diferente, digamos(^...^)
, mas não conseguiram convencer a maioria dos problemas de uso<...>
.)fonte
(^...^)
esta é uma cara feliz :)