web-dev-qa-db-fra.com

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

J'expérimentais avec des 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 taper le pack de paramètres de modèle.

En gros, je voudrais "stocker" le pack de paramètres dans un typedef, sans le déballer. C'est possible? Sinon, y a-t-il une raison pour laquelle cela n'est pas autorisé?

72
Luc Touraille

Une autre approche, 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()
{}
56
GManNickG

Je pense que la raison pour laquelle ce n'est pas permis est que ce serait compliqué et que vous pouvez contourner ce problème. Vous devez utiliser l'inversion de dépendance et rendre la structure stockant le pack de paramètres dans un modèle d'usine capable d'appliquer ce pack de paramètres à un autre modèle.

Quelque chose dans le sens de:

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;
8
Ben Voigt

Il s'agit d'une variante de l'astuce de spécialisation partielle soignée de GManNickG. Aucune 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() {}
2
jack