2017-01-18 1 views
3

Je voudrais créer une "version-conteneur" de std::integral_constant. C'est un type paramétrés avec un des paramètres de type élément et non de type:Créer un conteneur comme std :: integral_constant

enum class A { 
    a = 1 << 0, 
    b = 1 << 1, 
    c = 1 << 2 
}; 

template<typename T, T... Values> 
struct static_container final {}; 

template<typename T, T... Ts> 
constexpr auto make_static_container(T...) { // wrong 
    return static_container<T, Ts...>{}; 
} 

template<typename F, F... FF> 
void inline set(static_container<F, FF...>) { 
    std::cout << sizeof... (FF) << std::endl; 
} 

int main() { 
    constexpr static_container<A, A::a, A::b> sc1{}; //ok 
    constexpr auto sc2 = make_static_container(A::a, A::c); // not-ok 

    set(sc1);  
    set(sc2);  
} 

Ci-dessus vous pouvez voir que je peux créer sc1 avec le type explict.

Maintenant, j'aime avoir une fonction d'assistance pour créer un tel type sans spécifier le type enum (redondant).

La sortie est ici:

2 
0 

Tous les conseils?

+1

Quelle est l'erreur que vous obtenez et avec quel compilateur? – DeiDei

+1

Compile sur VS2015 – wally

+2

[Compile avec clang] (http://coliru.stacked-crooked.com/a/604bd7401ede4373) – wally

Répondre

3

En tant que suivi à votre commentaire en ce qui concerne std::integral_constant, voici ce que cela ressemblerait à ceci:

template<typename T, T... Values> 
constexpr auto make_static_container(std::integral_constant<T, Values>...) noexcept { 
    return static_container<T, Values...>{}; 
} 

le callsite va devoir changer puisque la fonction prend maintenant std::integral_constant<T> s plutôt que T de la directl y; il est un peu plus bruyant, mais des modèles variables garder d'être trop douloureuse: (. En aparté, la définition séparée de static_container::value dans la démo becomes unnecessary in C++17)

template<A a> 
using A_ = std::integral_constant<A, a>; 

template<A a> 
constexpr A_<a> a_{}; 

int main() { 
    // explicit construction via alias template: 
    constexpr auto sc1 = make_static_container(A_<A::a>{}, A_<A::b>{}); 
    // implicit construction via variable template: 
    constexpr auto sc2 = make_static_container(a_<A::a>, a_<A::c>); 

    set(sc1); 
    set(sc2); 
} 

Online Demo

+0

Idée intéressante avec les variables du modèle. – wimalopaan

+0

@wimalopaan: Jusqu'à récemment je n'avais pas d'opinion ou d'utilisation pour eux, mais en utilisant [Boost.Hana] (http://www.boost.org/libs/hana/) ces derniers temps m'a donné une nouvelle perspective. : -] – ildjarn

3

Votre problème est que vous ne passez pas les arguments de la fonction à la liste des arguments de modèle pour la création de valeur retournée

template<typename T, T... Ts> 
constexpr auto make_static_container(T... /* !!! unused values !!! */) { // wrong 
    return static_container<T, Ts...>{}; 
} 

donc le seul modèle est T déduit; pas de modèle non-type valeurs Ts sont déduites; donc le type retourné est

return static_container<T>{}; 

qui est avec des valeurs nulles.

Vous devriez être en mesure d'utiliser les arguments de la fonction et de les transmettre en tant que modèles et non en tant que paramètres de type; quelque chose comme

template<typename T0, typename ... Ts> 
constexpr auto make_static_container (T0 const t0, Ts const ... ts) 
{ return static_container<T0, t0, ts...>{}; } 

mais cela est impossible (pour autant que je sache) en C++ 11/C++ 14 parce que les valeurs t0/ts ne sont pas constexpr valeurs

+0

Oui, c'est en effet impossible, puisqu'une fonction constexpr doit aussi pouvoir être appelée dans un contexte non-constexpr. – wimalopaan

+0

Je me demande s'il pourrait y avoir une solution utilisant std :: integral_constant <> en tant que paramètre template de make_static_container avec une instanciation explicite de make_static_container au lieu d'une liste de paramètres .... Mais je ne peux pas le faire correctement. – wimalopaan