Можно ли "сохранить" пакет параметров шаблона, не расширяя его? - PullRequest
72 голосов
/ 14 января 2011

Я экспериментировал с вариабельными шаблонами 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 ]

56 голосов
/ 14 января 2011

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

#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()
{}
8 голосов
/ 14 января 2011

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

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

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;
3 голосов
/ 04 сентября 2013

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

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

2 голосов
/ 18 февраля 2013

Это разновидность хитрого подхода частичной специализации 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() {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...