2010-05-17 9 views
1

Je souhaite remplir les paramètres de modèle transmis à un modèle variadique dans un tableau de longueur fixe. A cette fin, je l'ai écrit la fonction d'aide suivante modèles deRemplir le conteneur avec les paramètres du modèle

template<typename ForwardIterator, typename T> 
void fill(ForwardIterator i) { } 

template<typename ForwardIterator, typename T, T head, T... tail> 
void fill(ForwardIterator i) { 
    *i = head; 
    fill<ForwardIterator, T, tail...>(++i); 
} 

le modèle de classe suivante

template<typename T, T... args> 
struct params_to_array; 

template<typename T, T last> 
struct params_to_array<T, last> { 
    static const std::size_t SIZE = 1; 
    typedef std::array<T, SIZE> array_type; 

    static const array_type params; 

private: 
    void init_params() { 
    array_type result; 
    fill<typename array_type::iterator, T, head, tail...>(result.begin()); 
    return result; 
    } 
}; 

template<typename T, T head, T... tail> 
struct params_to_array<T, head, tail...> { 
    static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1; 
    typedef std::array<T, SIZE> array_type; 

    static const array_type params; 

private: 
    void init_params() { 
    array_type result; 
    fill<typename array_type::iterator, T, last>(result.begin()); 
    return result; 
    } 
}; 

et initialisés les constantes statiques via

template<typename T, T last> 
const typename param_to_array<T, last>::array_type 
param_to_array<T, last>::params = 
    param_to_array<T, last>::init_params(); 

et

template<typename T, T head, T... tail> 
const typename param_to_array<T, head, tail...>::array_type 
param_to_array<T, head, tail...>::params = 
    param_to_array<T, head, tail...>::init_params(); 

maintenant la matrice

param_to_array<int, 1, 3, 4>::params 

est un std::array<int, 3> et contient les valeurs 1, 3 et 4. Je pense qu'il doit y avoir un moyen plus simple d'atteindre ce comportement. Aucune suggestion?

Edit: Comme Noah Roberts a suggéré dans sa réponse que je modifié mon programme comme ce qui suit: je l'ai écrit un nouveau comptage struct les éléments dans une liste de paramètres:

template<typename T, T... args> 
struct count; 

template<typename T, T head, T... tail> 
struct count<T, head, tail...> { 
    static const std::size_t value = count<T, tail...>::value + 1; 
}; 

template<typename T, T last> 
stuct count<T, last> { 
    static const std::size_t value = 1; 
}; 

et écrit la fonction suivante

template<typename T, T... args> 
std::array<T, count<T, args...>::value> 
params_to_array() { 
    std::array<T, count<T, args...>::value> result; 
    fill<typename std::array<T, count<T, args...>::value>::iterator, 
     T, args...>(result.begin()); 
    return result; 
} 

maintenant je avec

params_to_array<int, 10, 20, 30>() 

un std::array<int, 3> avec le contenu 10, 20 et 30. D'autres suggestions?

Répondre

2

Il n'est pas nécessaire de compter manuellement le nombre de types dans un jeu de paramètres, c'est à cela que sert l'opérateur sizeof.... De plus, je ferais le type iterator pour fill() déduisent, il n'y a pas besoin de le préciser explicitement:

template<typename T, typename FwdIt> 
void fill(FwdIt it) { } 

template<typename T, T head, T... tail, typename FwdIt> 
void fill(FwdIt it) { 
    *it = head; 
    fill<T, tail...>(++it); 
} 

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() { 
    std::array<T, sizeof...(args)> a; 
    fill<T, args...>(a.begin()); 
    return a; 
}; 

paramètre packs sont cependant également extensible dans des contextes initialiseur-liste, ce qui rend fill() redondante:

template<class T, T... args> 
std::array<T, sizeof...(args)> params_to_array() { 
    std::array<T, sizeof...(args)> a = {{args...}}; 
    return a; 
}; 
+0

+1 C'est génial! Je ne connaissais pas le 'sizeof ... (args)' du tout. – phlipsy

1

La seule raison pour laquelle je peux voir une spécialisation pour terminus param_to_array est cette ligne:

static const std::size_t SIZE = params_to_array<T, tail...>::SIZE + 1; 

Depuis votre métafonction de params_to_array crée le tableau que vous allez finir par les tableaux instanciation de taille N, N -1, ...., 1. Ainsi je pense que votre objet pourrait utiliser une aide de la composition et la règle de la responsabilité unique. Créez une autre métafonction capable de compter les éléments dans une liste de paramètres et de l'utiliser à la place de cette méthode. Ensuite, vous pouvez vous débarrasser de cette récursion dans params_to_array au moins.

+0

Vous avez raison! J'ai modifié (et donc simplifié) mon programme et cela a fonctionné. +1! – phlipsy

+0

Pas besoin d'une autre méta-fonction, il suffit d'utiliser 'sizeof ... (parameterPack)' en C++ 0x à la place :) –

Questions connexes