Pregunta
C ++ 0x permitirá que la plantilla tome un número arbitrario de argumentos. ¿Cuál es el mejor uso de esta función además de implementar tuplas?
Solución
- Tipo de impresión segura
- Reenvío de argumentos arbitrarios de muchos constructores en métodos de fábrica
- Tener clases base arbitrarias permite poner y quitar políticas útiles .
- Inicializando moviendo objetos mecanografiados heterogéneos directamente a un contenedor al tener un constructor de plantilla variable.
- Tener un operador literal que puede calcular un valor para un literal definido por el usuario (como " 10110b ").
Muestra a 3:
template<typename... T> struct flexible : T... { flexible(): T()... { } };
Muestra a 4:
struct my_container { template<typename... T> my_container(T&&... t) { } };
my_container c = { a, b, c };
Muestra a 5:
template<char... digits>
int operator "" b() { return convert<digits...>::value; }
Vea este código de ejemplo: aquí
Otros consejos
- Tipo seguro
printf
Permitir que cosas como Boost.Function tomen números arbitrarios de parámetros
Acabo de escribir un artículo sobre cómo implementar múltiples interfaces COM y mantener su código compacto y elegante con plantillas variadas C ++ 0x.
He implementado un NDArray (matriz N-dimentional) y tiene el método setSizes con recuento variado de argumentos. El uso de argumentos de plantilla variadic es más seguro que el uso de argumentos de función variadic, además, puedo controlar el recuento de parámetros pasados ??a esta función en tiempo de compilación solo con argumentos de plantilla variadic.
void setSizes(uintmax_t currentSize) {
static_assert(1 == NDimensions, "Invalid count of arguments given to setSizes.");
size_ = currentSize;
data_ = new NDArrayReferenceType[currentSize];
}
template <typename... Sizes>
void setSizes(uintmax_t currentSize, Sizes... sizes) {
static_assert(sizeof...(Sizes) + 1 == NDimensions, "Invalid count of arguments given to setSizes.");
size_ = currentSize;
data_ = new NDArrayReferenceType[currentSize];
for (uintmax_t i = 0; i < currentSize; i++) {
data_[i]->setSizes(sizes...);
}
}
También he implementado un contenedor de constructor universal para mi SmartPointer hecho a sí mismo. Se ajusta sobre todo constructor definido por el usuario del tipo de puntero sin formato.
template <typename TSmartPointer, typename... Args>
static inline void initialize(TSmartPointer *smartPointer, Args... args) {
smartPointer->pointer_ = new typename TSmartPointer::PointerType(std::forward<Args>(args)...);
smartPointer->__retain();
}
Este código parece no ser obvio, esto es parte del inicializador del SmartPointer para el caso de que SmartPointer llame automáticamente al constructor del puntero en la adquisición del SmartPointer (RAII). En el caso de clases abstractas, no puede llamar al constructor.
Entonces, si tengo un tipo AbstractObject, que es SmartPointer de una clase abstracta, y el tipo ConcreteObject, que es SmartPointer de clase con un constructor que toma dos ints, puedo escribir el siguiente código:
AbstractObject object = ConcreteObject(42, 42);
Es como C # y Java (pero con RAII) y funciona para mí en C ++ / GCC 4.8 =)
Escriba la seguridad de cada llamada con un número de argumento dinámico.
La impresión de tipo seguro se ha mencionado en otras respuestas, pero en general se pueden usar plantillas variadas para implementar funciones de formato que no requieren pasar información de tipo a través de especificadores de formato. Por ejemplo, la biblioteca de formato C ++ implementa funciones de formato similares a las de Python str.format :
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
además de impresión segura f. Los tipos de argumentos se capturan automáticamente utilizando plantillas variadas en C ++ 11.
Esto hace que los especificadores de printf como lld
o notorious PRIdPTR
sean innecesarios y en lugar de
std::printf("Local number: %" PRIdPTR "\n\n", someIntPtr);
uno simplemente puede usar
fmt::printf("Local number: %d\n\n", someIntPtr);
Descargo de responsabilidad : soy el autor de esta biblioteca