71 votes

Est-il possible de "stocker" un pack de paramètres de modèle sans le développer ?

J'expérimentais les modèles variadiques C++0x lorsque je suis tombé sur ce problème :

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 donne une erreur lorsque j'essaie de typedéfinir le paquet de paramètres du modèle.

En fait, je voudrais "stocker" le paquet de paramètres dans un typedef, sans le déballer. Est-ce possible ? Si non, y a-t-il une raison pour laquelle cela n'est pas autorisé ?

56voto

GManNickG Points 155079

Une autre approche, qui est légèrement plus générique que celle de Ben, est la suivante :

#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()
{}

9voto

Ben Voigt Points 151460

Je pense que la raison pour laquelle ce n'est pas autorisé est que cela serait désordonné, et vous pouvez le contourner. Vous devez utiliser l'inversion de dépendance et faire en sorte que la structure stockant le pack de paramètres dans un modèle de fabrique soit capable d'appliquer ce pack de paramètres à un autre modèle.

Quelque chose du genre :

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;

3voto

Werner Erasmus Points 984

J'ai trouvé l'idée de Ben Voigt très utile dans mes propres efforts. Je l'ai légèrement modifiée pour qu'elle ne s'applique pas seulement aux tuples. Pour les lecteurs d'ici, c'est peut-être une modification évidente, mais cela peut valoir la peine de la montrer :

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;
};

Le nom TypeWithList vient du fait que le type est maintenant instancié avec une liste précédente.

2voto

jack Points 185

C'est une variante de l'astuce de spécialisation partielle de GManNickG. Pas de délégation, et vous obtenez plus de sécurité de type en exigeant l'utilisation de votre structure 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() {}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X