Можно ли "хранить" пакет параметров шаблона без его расширения?
я экспериментировал с C++0x вариативными шаблонами, когда я наткнулся на эту проблему:
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 дает мне ошибку, когда я пытаюсь typedef пакет параметров шаблона.
в принципе, я хотел бы "хранить" пакет параметров в typedef, не распаковывая его. Возможно ли это? Если нет, то есть ли какая-то причина, почему это не допускается?
4 ответа:
другой подход, который немного более общий, чем у Бена, заключается в следующем:
#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() {}
Я думаю, что причина, по которой это не разрешено, заключается в том, что это будет грязно, и вы можете обойти это. Вам нужно использовать инверсию зависимостей и сделать структуру, хранящую пакет параметров в Заводском шаблоне, способной применить этот пакет параметров к другому шаблону.
что-то вроде:
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;
Это вариация аккуратного трюка частичной специализации GManNickG. Нет делегирования, и вы получаете больше безопасности типов, требуя использования вашей структуры 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() {}
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; };
имя TypeWithList связано с тем, что тип теперь создается с предыдущим списком.