Como posso escrever uma função que aceita um número variável de argumentos? Isso é possível, como?
c++
variadic-functions
nunos
fonte
fonte
Respostas:
Você provavelmente não deveria, e provavelmente pode fazer o que deseja fazer de maneira mais segura e simples. Tecnicamente, para usar o número variável de argumentos em C, você inclui stdarg.h. A partir disso, você obterá o
va_list
tipo, bem como três funções que operam nele chamadasva_start()
,va_arg()
eva_end()
.Se você me perguntar, isso é uma bagunça. Parece ruim, inseguro e cheio de detalhes técnicos que nada têm a ver com o que você está tentando conceitualmente alcançar. Em vez disso, considere o uso de sobrecarga ou herança / polimorfismo, padrão do construtor (como em
operator<<()
fluxos) ou argumentos padrão, etc. Todos são mais seguros: o compilador fica sabendo mais sobre o que você está tentando fazer, para que haja mais ocasiões em que ele pode parar antes de explodir sua perna.fonte
...
sintaxe?printf()
, por exemplo, a função analisa o argumento da string para tokens especiais para descobrir quantos argumentos extras ele deve esperar na lista de argumentos da variável.<cstdarg>
em C ++ em vez de<stdarg.h>
No C ++ 11, você tem duas novas opções, conforme a página de referência das funções Variadic na seção Alternativas :
Abaixo está um exemplo mostrando as duas alternativas ( veja ao vivo ):
Se você estiver usando
gcc
ouclang
podemos usar a variável mágica PRETTY_FUNCTION para exibir a assinatura de tipo da função que pode ser útil para entender o que está acontecendo. Por exemplo, usando:seria o resultado int a seguir para funções variadas no exemplo ( veja ao vivo ):
No Visual Studio, você pode usar o FUNCSIG .
Atualizar pré C ++ 11
Antes do C ++ 11, a alternativa para std :: initializer_list seria std :: vector ou um dos outros contêineres padrão :
e a alternativa para modelos variados seriam funções variadas, embora não sejam de tipo seguro e, em geral, propensas a erros e possam ser inseguras de usar, mas a única outra alternativa em potencial seria usar argumentos padrão , embora isso tenha uso limitado. O exemplo abaixo é uma versão modificada do código de exemplo na referência vinculada:
O uso de funções variadas também vem com restrições nos argumentos que você pode passar, detalhadas no rascunho do padrão C ++ na seção
5.2.2
Chamada de função, parágrafo 7 :fonte
typename
vs estáclass
acima do intencional? Se sim, por favor explique.initializer_list
recursiva?Uma solução C ++ 17: segurança de tipo completo + sintaxe de chamada agradável
Desde a introdução de modelos variados no C ++ 11 e expressões de dobras no C ++ 17, é possível definir uma função de modelo que, no site do chamador, é possível chamar como se fosse uma função varídica, mas com as vantagens de :
Aqui está um exemplo para tipos de argumentos mistos
E outro com correspondência de tipo imposta para todos os argumentos:
Mais Informações:
fonte
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
eTail...
é a mesma ", onde " é a mesma " significastd::conjunction<std::is_same<Head, Tail>...>
. Leia esta última definição como "Head
é igual a todosTail...
".No c ++ 11, você pode fazer:
inicializador de lista FTW!
fonte
No C ++ 11, existe uma maneira de criar modelos de argumentos variáveis que levam a uma maneira realmente elegante e segura de digitar funções de argumentos variáveis. O próprio Bjarne fornece um bom exemplo de printf usando modelos de argumentos variáveis no C ++ 11FAQ .
Pessoalmente, considero isso tão elegante que nem sequer me incomodaria com uma função de argumento variável em C ++ até que o compilador tenha suporte para modelos de argumento de variável C ++ 11.
fonte
,
operador com expressões fold). Caso contrário, acho que não.Funções variadas do estilo C são suportadas em C ++.
No entanto, a maioria das bibliotecas C ++ usa um idioma alternativo, por exemplo, enquanto a
'c' printf
função recebe argumentos variáveis, oc++ cout
objeto usa<<
sobrecarga que aborda segurança de tipo e ADTs (talvez ao custo da simplicidade da implementação).fonte
std::initializer_lists
... E isso já está introduzindo uma enorme complexidade em uma tarefa simples.Além de varargs ou sobrecarga, você pode considerar agregar seus argumentos em um std :: vector ou em outros contêineres (std :: map por exemplo). Algo assim:
Dessa maneira, você obteria segurança de tipo e o significado lógico desses argumentos variáveis seria aparente.
Certamente, essa abordagem pode ter problemas de desempenho, mas você não deve se preocupar com eles, a menos que tenha certeza de que não pode pagar o preço. É uma espécie de abordagem "Pythonic" para c ++ ...
fonte
A única maneira é através do uso de argumentos de variável de estilo C, conforme descrito aqui . Observe que essa não é uma prática recomendada, pois não é tipicamente segura e propensa a erros.
fonte
Não existe uma maneira C ++ padrão de fazer isso sem recorrer a varargs (
...
) no estilo C.É claro que existem argumentos padrão que parecem "número variável de argumentos", dependendo do contexto:
Todas as quatro chamadas de função são chamadas
myfunc
com um número variável de argumentos. Se nenhum for fornecido, os argumentos padrão serão usados. Observe, no entanto, que você só pode omitir argumentos à direita. Não há como, por exemplo, omitiri
e dar apenasj
.fonte
É possível que você queira sobrecarregar ou parâmetros padrão - defina a mesma função com parâmetros padrão:
Isso permitirá que você chame o método com uma das quatro chamadas diferentes:
... ou você pode procurar as convenções de chamada v_args de C.
fonte
Se você souber o número de argumentos que serão fornecidos, sempre poderá usar alguma sobrecarga de função, como
e assim por diante...
fonte
Usando modelos variados, exemplo para reproduzir
console.log
como visto em JavaScript:Nome do arquivo, por exemplo
js_console.h
:fonte
Como outros já disseram, varargs no estilo C. Mas você também pode fazer algo semelhante com argumentos padrão.
fonte
Agora é possível ... usando boost any e templates Nesse caso, o tipo de argumentos pode ser misturado
fonte
Combine as soluções C e C ++ para a opção semanticamente mais simples, com desempenho e mais dinâmica. Se você errar, tente outra coisa.
O usuário escreve:
Semanticamente, isso parece e se sente exatamente como uma função n-argument. Sob o capô, você pode desempacotá-lo de uma maneira ou de outra.
fonte
Também poderíamos usar um initializer_list se todos os argumentos forem const e do mesmo tipo
fonte
Versão simples
fonte