c++ templates c++11 variadic-templates

c++ - ¿Es posible "almacenar" un paquete de parámetros de plantilla sin expandirlo?



templates c++11 (4)

Creo que la razón por la que no está permitido es que sería complicado y puedes evitarlo. Debe usar la inversión de dependencia y hacer que la estructura que almacena el paquete de parámetros en una plantilla de fábrica pueda aplicar ese paquete de parámetros a otra plantilla.

Algo como:

template < typename ...Args > struct identities { template < template<typename ...> class T > struct apply { typedef T<Args...> type; }; }; template < template<template<typename ...> class> class T > struct convert_in_tuple { typedef typename T<std::tuple>::type type; }; typedef convert_in_tuple< identities< int, float >::apply >::type int_float_tuple;

Estaba experimentando con C ++ 0x plantillas variadas cuando tropecé con este problema:

template < typename ...Args > struct identities { typedef Args type; //compile error: "parameter packs not expanded with ''...'' }; //The following code just shows an example of potential use, but has no relation //with what I am actually trying to achieve. template < typename T > struct convert_in_tuple { typedef std::tuple< typename T::type... > type; }; typedef convert_in_tuple< identities< int, float > >::type int_float_tuple;

GCC 4.5.0 me da un error cuando intento tipear el paquete de parámetros de la plantilla.

Básicamente, me gustaría "almacenar" el paquete de parámetros en un typedef, sin desempaquetarlo. ¿Es posible? Si no, ¿hay alguna razón por la cual esto no está permitido?


Esta es una variación del truco de especialización parcial ordenada de GManNickG. Sin delegación, y obtiene más seguridad de tipo al requerir el uso de su estructura variadic_typedef.

#include <tuple> template<typename... Args> struct variadic_typedef {}; template<typename... Args> struct convert_in_tuple { //Leaving this empty will cause the compiler //to complain if you try to access a "type" member. //You may also be able to do something like: //static_assert(std::is_same<>::value, "blah") //if you know something about the types. }; template<typename... Args> struct convert_in_tuple< variadic_typedef<Args...> > { //use Args normally typedef std::tuple<Args...> type; }; typedef variadic_typedef<int, float> myTypes; typedef convert_in_tuple<myTypes>::type int_float_tuple; //compiles //typedef convert_in_tuple<int, float>::type int_float_tuple; //doesn''t compile int main() {}


He encontrado la idea de Ben Voigt muy útil en mis propios esfuerzos. Lo he modificado ligeramente para que sea general, no solo para las tuplas. Para los lectores aquí podría ser una modificación obvia, pero puede valer la pena mostrar:

template <template <class ... Args> class T, class ... Args> struct TypeWithList { typedef T<Args...> type; }; template <template <class ... Args> class T, class ... Args> struct TypeWithList<T, VariadicTypedef<Args...>> { typedef typename TypeWithList<T, Args...>::type type; };

El nombre TypeWithList se deriva del hecho de que el tipo ahora está instanciado con una lista previa.


Otro enfoque, que es un poco más genérico que el de Ben, es el siguiente:

#include <tuple> template <typename... Args> struct variadic_typedef { // this single type represents a collection of types, // as the template arguments it took to define it }; template <typename... Args> struct convert_in_tuple { // base case, nothing special, // just use the arguments directly // however they need to be used typedef std::tuple<Args...> type; }; template <typename... Args> struct convert_in_tuple<variadic_typedef<Args...>> { // expand the variadic_typedef back into // its arguments, via specialization // (doesn''t rely on functionality to be provided // by the variadic_typedef struct itself, generic) typedef typename convert_in_tuple<Args...>::type type; }; typedef variadic_typedef<int, float> myTypes; typedef convert_in_tuple<myTypes>::type int_float_tuple; int main() {}