¿Cómo puedo escribir una función que acepte un número variable de argumentos? ¿Es esto posible, cómo?
c++
variadic-functions
nunos
fuente
fuente
Respuestas:
Probablemente no deberías, y probablemente puedas hacer lo que quieras hacer de una manera más segura y sencilla. Técnicamente, para usar un número variable de argumentos en C, incluye stdarg.h. A partir de eso, obtendrá el
va_list
tipo y las tres funciones que operan en él llamadasva_start()
,va_arg()
yva_end()
.Si me preguntas, esto es un desastre. Se ve mal, es inseguro y está lleno de detalles técnicos que no tienen nada que ver con lo que estás tratando de lograr conceptualmente. En su lugar, considere usar sobrecarga o herencia / polimorfismo, patrón de construcción (como en las
operator<<()
secuencias) o argumentos predeterminados, etc. Todo esto es más seguro: el compilador conoce más sobre lo que está tratando de hacer, por lo que hay más ocasiones en que puede detenerse antes de que te vueles la pierna.fuente
...
sintaxis?printf()
, por ejemplo, la función analiza el argumento de cadena para tokens especiales para determinar cuántos argumentos adicionales debe esperar en la lista de argumentos variables.<cstdarg>
en C ++ en lugar de<stdarg.h>
En C ++ 11 tiene dos nuevas opciones, como dice la página de referencia de funciones Variadic en la sección Alternativas :
A continuación se muestra un ejemplo que muestra ambas alternativas ( verlo en vivo ):
Si está utilizando
gcc
oclang
podemos utilizar la variable mágica PRETTY_FUNCTION para mostrar la firma de tipo de la función que puede ser útil para comprender lo que está sucediendo. Por ejemplo usando:daría como resultado int following para funciones variadas en el ejemplo ( verlo en vivo ):
En Visual Studio puedes usar FUNCSIG .
Actualizar Pre C ++ 11
Pre C ++ 11 la alternativa para std :: initializer_list sería std :: vector o uno de los otros contenedores estándar :
y la alternativa para plantillas variadas serían funciones variadas, aunque no son de tipo seguro y en general propensas a errores y pueden ser inseguras de usar, pero la única otra alternativa potencial sería usar argumentos predeterminados , aunque eso tiene un uso limitado. El siguiente ejemplo es una versión modificada del código de muestra en la referencia vinculada:
El uso de funciones variadas también viene con restricciones en los argumentos que puede pasar, que se detalla en el borrador del estándar C ++ en la sección
5.2.2
Llamada de función, párrafo 7 :fuente
typename
vs esclass
superior al intencional? Si es así, por favor explique.initializer_list
recursivo?Una solución C ++ 17: seguridad de tipo completo + buena sintaxis de llamadas
Desde la introducción de plantillas variadas en C ++ 11 y expresiones de plegado en C ++ 17, es posible definir una función de plantilla que, en el sitio de la persona que llama, es invocable como si fuera una función varídica pero con las ventajas de :
Aquí hay un ejemplo para tipos de argumentos mixtos
Y otro con concordancia de tipo forzada para todos los argumentos:
Más información:
fuente
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
yTail...
son lo mismo ", donde " son lo mismo " significastd::conjunction<std::is_same<Head, Tail>...>
. Lea esta última definición como "Head
es lo mismo que todosTail...
".en c ++ 11 puedes hacer:
lista inicializador FTW!
fuente
En C ++ 11 hay una manera de hacer plantillas de argumentos variables que conducen a una forma realmente elegante y segura de tener funciones de argumentos variables. El propio Bjarne da un buen ejemplo de printf usando plantillas de argumentos variables en C ++ 11FAQ .
Personalmente, considero esto tan elegante que ni siquiera me molestaría con una función de argumento variable en C ++ hasta que ese compilador sea compatible con las plantillas de argumento variable de C ++ 11.
fuente
,
operador con expresiones de pliegue). De lo contrario, no lo creo.Las funciones variadas de estilo C son compatibles con C ++.
Sin embargo, la mayoría de las bibliotecas de C ++ usan un idioma alternativo, por ejemplo, mientras que la
'c' printf
función toma argumentos variables, elc++ cout
objeto usa una<<
sobrecarga que aborda la seguridad de tipos y los ADT (quizás a costa de la simplicidad de implementación).fuente
std::initializer_lists
... Y esto ya está introduciendo una complejidad masiva en una tarea simple.Además de varargs o sobrecarga, podría considerar agregar sus argumentos en un std :: vector u otros contenedores (std :: map por ejemplo). Algo como esto:
De esta forma, obtendría seguridad de tipo y el significado lógico de estos argumentos variados sería evidente.
Seguramente este enfoque puede tener problemas de rendimiento, pero no debe preocuparse por ellos a menos que esté seguro de que no puede pagar el precio. Es una especie de enfoque "pitón" para c ++ ...
fuente
La única forma es mediante el uso de argumentos variables de estilo C, como se describe aquí . Tenga en cuenta que esta no es una práctica recomendada, ya que no es segura para escribir y propensa a errores.
fuente
No hay una forma estándar de C ++ para hacer esto sin recurrir a varargs de estilo C (
...
).Por supuesto, hay argumentos predeterminados que "parecen" como un número variable de argumentos según el contexto:
Las cuatro llamadas a funciones llaman
myfunc
con un número variable de argumentos. Si no se proporciona ninguno, se utilizan los argumentos predeterminados. Sin embargo, tenga en cuenta que solo puede omitir argumentos finales. No hay forma, por ejemplo, de omitiri
y dar soloj
.fuente
Es posible que desee una sobrecarga o parámetros predeterminados: defina la misma función con los parámetros predeterminados:
Esto le permitirá llamar al método con una de cuatro llamadas diferentes:
... o podrías estar buscando las convenciones de llamadas v_args de C.
fuente
Si conoce el rango de número de argumentos que se proporcionarán, siempre puede usar alguna sobrecarga de funciones, como
y así...
fuente
Usando plantillas variadas, ejemplo para reproducir
console.log
como se ve en JavaScript:Nombre de archivo, por ejemplo
js_console.h
:fuente
Como han dicho otros, varargs de estilo C. Pero también puede hacer algo similar con argumentos predeterminados.
fuente
Es posible ahora ... usando boost any y templates En este caso, el tipo de argumentos se puede mezclar
fuente
Combine las soluciones C y C ++ para obtener la opción semánticamente más simple, eficiente y dinámica. Si te equivocas, prueba con otra cosa.
El usuario escribe:
Semánticamente, esto se ve y se siente exactamente como una función de argumento n. Debajo del capó, puede desempacarlo de una manera u otra.
fuente
También podríamos usar una initializer_list si todos los argumentos son constantes y del mismo tipo
fuente
Versión simple
fuente