Pergunta simples para a qual não consegui encontrar resposta na rede. Em macros de argumento variadic, como encontrar o número de argumentos? Estou bem com pré-processador boost, se tiver a solução.
Se fizer diferença, estou tentando converter o número variável de argumentos da macro para aumentar a sequência, lista ou matriz do pré-processador para reprocessamento posterior.
c++
c
c-preprocessor
variadic-macros
Anycorn
fonte
fonte
__typeof__
para fazê-lo funcionar pelo menos em alguns compiladoresRespostas:
Na verdade, isso depende do compilador e não é compatível com nenhum padrão.
Aqui, no entanto, você tem uma implementação de macro que faz a contagem:
fonte
#define EXPAND(x) x
#define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 9,8,7,6,5,4,3,2,1,0))
`` `PP_NARG()
falha em retornar 0. As soluçõesGET_ARG_COUNT()
&Y_TUPLE_SIZE()
funcionam.PP_NARG()
não retorna 0" ... não é necessariamente um problema. Pode-se dizer quePP_NARG()
deve retornar 1 pela mesma razão quePP_NARG(,)
deve retornar 2. Detectar 0 pode ser útil em alguns casos, mas as soluções parecem ser menos gerais (exigindo que o primeiro token seja colável; o que pode ou não ser adequado dependendo do que você está usando), ou específico de implementação (como requerer o truque de remoção e colagem de vírgula do gnu).Eu geralmente uso essa macro para encontrar vários parâmetros:
Exemplo completo:
É um código C99 totalmente válido. Porém, tem uma desvantagem - você não pode chamar a macro
SUM()
sem parâmetros, mas o GCC tem uma solução para isso - veja aqui .Portanto, no caso do GCC, você precisa definir macros como esta:
e funcionará mesmo com lista de parâmetros vazia
fonte
sizeof(int) != sizeof(void *)
?{__VA_ARGS__}
paraint[]
, é justoint[]
, independentemente do conteúdo real de__VA_ARGS__
##
não é necessário no VS2017, pois um vazio__VA_ARGS__
removerá automaticamente qualquer vírgula anterior.Se você estiver usando C ++ 11 e precisar do valor como uma constante de tempo de compilação C ++, uma solução muito elegante é esta:
Observação: a contagem ocorre inteiramente em tempo de compilação e o valor pode ser usado sempre que um inteiro em tempo de compilação for necessário, por exemplo, como um parâmetro de modelo para std :: array.
fonte
sizeof((int[]){__VA_ARGS__})/sizeof(int)
sugerido acima, ele funciona mesmo quando os argumentos não podem ser todos expressosint
.#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
Por conveniência, aqui está uma implementação que funciona para 0 a 70 argumentos e funciona no Visual Studio, GCC e Clang . Acredito que funcionará no Visual Studio 2010 e posteriores, mas só testei no VS2013.
fonte
__VA_ARGS__
" (que em C ++, é tecnicamente uma extensão de compilador (quase universal, padrão de fato ) até C ++ 20). A maioria (todos?) Dos compiladores permite comprimento zero, mas engasga com a vírgula final se a lista estiver vazia (e sobrecarregada##
como um proto-__VA_OPT__
, para remover a vírgula neste caso); A versão de MSVC da extensão simplesmente não engasgar com a vírgula (mas vai engasgar com o sobrecarregado##
). Compare MSVCunused, __VA_ARGS__
com não-MSVC0, ## __VA_ARGS__
; nenhum é mais correto, o problema é que eles são diferentes.Existem algumas soluções C ++ 11 para encontrar o número de argumentos em tempo de compilação, mas estou surpreso ao ver que ninguém sugeriu algo tão simples como:
Isso também não requer a inclusão do
<tuple>
cabeçalho.fonte
VA_COUNT(&,^,%)
. Além disso, se você está contando por meio de uma função, não vejo sentido em fazer uma macro.isso funciona com 0 argumentos com gcc / llvm. [links são burros]
O Visual Studio parece estar ignorando o operador ## usado para consumir o argumento vazio. Você provavelmente pode contornar isso com algo como
fonte
##__VA_ARGS__
comer a vírgula antes de se__VA_ARGS__
estiver vazio é uma extensão do GCC. Não é o comportamento padrão.Com extensão msvc:
Funciona para 0 - 32 argumentos. Esse limite pode ser facilmente estendido.
EDITAR: versão simplificada (funciona no VS2015 14.0.25431.01 Atualização 3 e gcc 7.4.0) até 100 argumentos para copiar e colar:
fonte
Y_TUPLE_SIZE("Hello")
, tornando-a bastante inviável. Eu concordo com @osirisgothra.Estou assumindo que cada argumento para VA_ARGS será separado por vírgulas. Em caso afirmativo, acho que essa deve funcionar como uma maneira bastante limpa de fazer isso.
Funcionou para mim no godbolt para clang 4 e GCC 5.1. Isso será calculado em tempo de compilação, mas não será avaliado para o pré-processador. Portanto, se você está tentando fazer algo como um FOR_EACH , isso não funcionará.
fonte
NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)
!!! Cada string de arg não pode ter alguns outros símbolos, como','
entretantoint count = NUMARGS( foo(1, 2) );
produz 2 em vez de 1. godbolt.org/z/kpBuOmaqui uma maneira simples de contar 0 ou mais argumentos de VA_ARGS , meu exemplo assume um máximo de 5 variáveis, mas você pode adicionar mais se quiser.
fonte
VA_ARGS_NUM
é usado com macro: se eu tiver#define TEST
(ou seja, vazioTEST
) eVA_ARGS_NUM(TEST)
não retornar 0 (zero) quando usado em#if
:(Você pode stringfy e contar tokens:
fonte
Na verdade, o pré-processador Boost tem isso a partir do Boost 1.49, como
BOOST_PP_VARIADIC_SIZE(...)
. Funciona até o tamanho 64.Sob o capô, é basicamente o mesmo que a resposta de Kornel Kisielewicz .
fonte
__VA_OPT__
ou as extensões do compilador para##__VA_ARGS__
remover a vírgula anterior, por exemplo: godbolt.org/z/X7OvnKEu descobri que as respostas aqui ainda estão incompletas.
A implementação portátil mais próxima que encontrei aqui é: pré-processador C ++ __VA_ARGS__ número de argumentos
Mas não funciona com o argumento zero no GCC sem pelo menos o
-std=gnu++11
parâmetro da linha de comando.Então, decidi mesclar essa solução com isso: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
https://godbolt.org/z/3idaKd
c++11
,msvc 2015
,gcc 4.7.1
,clang 3.0
fonte