- теперь любой вариационный пакет может быть сопоставлен с

периментировал с вариабельными шаблонами 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, не распаковывая его. Является ли это возможным? Если нет, есть ли какая-то причина, почему это не разрешено?

Ответы на вопрос(4)

Я немного изменил его, чтобы сделать его общим, а не просто кортежами. Для читателей здесь это может быть очевидной модификацией, но, возможно, стоит показать:

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 проистекает из того факта, что тип теперь создается с помощью предыдущего списка.

делегирования, и вы получите больше безопасности типов, требуя использования вашей структуры 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() {}
 Luc Touraille18 февр. 2013 г., 09:26
В ответе @ GManNickG не было рекурсии, и я думаю, что возможность использовать необработанный пакет параметров вместоvariadic_typedef должен был быть фичей. Следовательно, я бы сказал, что этот ответ скорее унижение, чем уточнение ...
 jack05 мар. 2013 г., 18:26
Я понимаю, что опция не использовать variadic_typedef была предназначена для функции, но функция одного человека - ошибка другого человека. Причина, по которой я был в этой теме, заключалась в том, чтобы найти способ сделать именно то, что мой ответ делает здесь. Кроме того, в решении @ GManNickG есть один рекурсивный «вызов» - когда variadic_typdef частичная специализация convert_in_tuple «делегирует» в неспециализированную версию. Без этого все немного проще. И, наконец, я выбрал слово «уточнение» не для того, чтобы сформулировать свое решение лучше, а как более конкретное. Я изменил свою формулировку, чтобы отразить это.
 Yakk - Adam Nevraumont12 авг. 2013 г., 17:36
Вы можете удалить зависимость отvariadic_typedef заconvert_in_tuple - возьмиtemplate<typename Pack> struct convert_in_tuple {};затем специализируюсьtemplate<template<typename...>class Pack, typename...Args> struct convert_in_tuple<Pack<Args...>> { typedef std::tuple<Args> type; } - теперь любой вариационный пакет может быть сопоставлен сtuple.

что причина, по которой это запрещено, заключается в том, что это будет грязно, и вы можете обойти это. Вам нужно использовать инверсию зависимостей и сделать структуру, хранящую пакет параметров в заводском шаблоне, способной применить этот пакет параметров к другому шаблону.

Что-то вроде:

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;
 Ben Voigt14 янв. 2011 г., 15:53
@Luc: отредактировано, чтобы быть шаблоном шаблона. Заменаtypename с участиемclass чувствует себя немного сомнительно, так как проект говорит, что "нет никакой смысловой разницы междуclass а такжеtemplate вШаблон-параметр. ", не могли бы вы попробовать этот новый код?
 Luc Touraille14 янв. 2011 г., 16:35
Действительно, в п. 14.1.2 стандарта говорится, что междуclass а такжеtypename, но чуть выше (в §14.1.1), синтаксис допускает толькоclass ключевое слово в объявлении параметра шаблона шаблона. Хотя это может показаться противоречивым, я думаю, что логическое обоснование, как я уже говорил ранее, заключается в том, что параметр шаблона не может быть любого типа (например, он не может бытьint или жеbool), поэтому, возможно, комитет решил, что использованиеtypename будет вводить в заблуждение. В любом случае, давайте вернемся к теме :)!
 Ben Voigt14 янв. 2011 г., 16:10
@Luc: Получил его для компиляции в gcc 4.5.2 в виртуальной машине, спасибо за указатели. Теперь изо всех сил пытается получить копию + вставить из виртуальной машины, чтобы работать ...
 Luc Touraille14 янв. 2011 г., 16:01
Я не могу найти его в стандарте, но я думаю, что я помню, что для параметров шаблона шаблона вам нужно использоватьclass и нетtypename (потому что тип шаблона неизбежно является классом, а не типом).
 Luc Touraille14 янв. 2011 г., 15:51
Я попробовал ваш код на GCC 4.5, вам просто нужно изменитьtypename T вclass T и изменитьconvert_in_tuple параметр, который будет шаблоном шаблона:template < template< template < typename ... > class > class T > struct convert_in_tuple {...} (!).
Решение Вопроса

который немного более общий, чем у Бена, заключается в следующем:

#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()
{}
 Luc Touraille15 янв. 2011 г., 21:13
Очень хороший обходной путь, я не думал об использовании частичной специализации шаблона!
 Ben Voigt15 янв. 2011 г., 01:31
Хорошо, очень похоже на то, что первоначально пробовал OP.
 Jason20 авг. 2011 г., 17:10
@GMan: быстрый вопрос ... это было полезно, но должна быть частично специализированная версияtypedef typename convert_in_tuple<Args...>::type type;или это не имеет значения?
 user281381028 янв. 2015 г., 20:15
Я не понимаю, как это решает проблему ОП. Структура convert_in_tuple содержит псевдоним псевдонима кортежа. Тип, который он представляет, - это кортеж с пакетом параметров Args ..., а не сам пакет параметров Args ....
 Yakk - Adam Nevraumont12 авг. 2013 г., 17:33
Я был бы немного обеспокоен: хотя очень заманчиво сказать «рассматривать список типов или экземпляр определенного типа, который содержит список, как одно и то же», в моем опыте вещи, как правило, беспорядочно взрываются, когда вы сделай это. В качестве примера представим список длины 1, содержащийvariadic_typedef и как это взаимодействует с приведенным выше кодом. Теперь представьте список типов, каждый из которых передается вconvert_in_tuple и как это взаимодействует с приведенным выше кодом. Если вы начнете настраивать несколько уровней косвенности, обращение с контейнером и содержимым как взаимозаменяемым вызывает проблемы.

Ваш ответ на вопрос