2017-06-30 4 views
1

J'ai une classe qui reçoit des modèles variadiques du même type. Chacun de ces types ont une valeur imbriquée qui doit être unique:Affirmez systématiquement que la valeur imbriquée du modèle variadique est unique

template <SomeEnum _se, int _val> 
struct Pack 
{ 
    enum {val_se = _se}; 
    enum {val = _val}; 
}; 

int main() 
{ 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<C_SE, 3>> tm_abc; // OK 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<A_SE, 3>> tm_aba; // Should fail (first and last Pack are templated with A_SE) 

    (void)tm_abc; 
    (void)tm_aba; 
    return (0); 
} 

Le code de test complet:

#include <cstdio> 

template <typename ... ArgPacks> 
class TypeMe 
{ 
public: 
    TypeMe(); 
private: 
    template <typename ... APs> 
    void cycleAPs(); 

    template <typename AP> 
    void cycleAP(); 
}; 

template <typename ... ArgPacks> 
TypeMe<ArgPacks...>::TypeMe() 
{ 
    // Maybe the static assertion should go here 
    cycleAPs<ArgPacks...>(); 
} 

template <typename ... ArgPacks> 
template <typename ... APs> 
void TypeMe<ArgPacks...>::cycleAPs() 
{ 
    int _[] = {0, (cycleAP<APs>(), 0)...}; 
    (void)_; 
    return ; 
} 

template <typename ... ArgPacks> 
template <typename AP> 
void TypeMe<ArgPacks...>::cycleAP() 
{ 
    printf("SomeEnum = %d, Val = %d\n", static_cast<int>(AP::val_se), AP::val); 
    return ; 
} 

enum SomeEnum 
{ 
    A_SE, 
    B_SE, 
    C_SE, 
    MAX 
}; 

template <SomeEnum _se, int _val> 
struct Pack 
{ 
    enum {val_se = _se}; 
    enum {val = _val}; 
}; 

int main() 
{ 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<C_SE, 3>> tm_abc; // OK 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<A_SE, 3>> tm_aba; // Should fail (first and last Pack are templated with A_SE) 

    (void)tm_abc; 
    (void)tm_aba; 
    return (0); 
} 

Est-il possible, en C++ 0x, vérifier au moment de la compilation que chaque du Pack :: val_se sont différents? ou avec C++ 11?

Merci pour la lecture

modifier:

Même code mais avec réponse @MadScientist, grâce

#include <cstdio> 


template <typename ...Ts> 
struct are_mutually_different; 

template <typename T> 
struct are_mutually_different<T> 
{ 
    static const bool value = true; 
}; 

template <typename T1, typename T2, typename ...Ts> 
struct are_mutually_different<T1, T2, Ts...> 
{ 
    static const bool value = (T1::val_se != T2::val_se) && 
          are_mutually_different<T1, Ts...>::value && 
          are_mutually_different<T2, Ts...>::value; 
}; 


template <typename ... ArgPacks> 
class TypeMe 
{ 
public: 
    TypeMe(); 
private: 
    template <typename ... APs> 
    void cycleAPs(); 

    template <typename AP> 
    void cycleAP(); 
}; 

template <typename ... ArgPacks> 
TypeMe<ArgPacks...>::TypeMe() 
{ 
    static_assert(are_mutually_different<ArgPacks...>::value, "!"); // <3 
    // Maybe the static assertion should go here 
    cycleAPs<ArgPacks...>(); 
} 

template <typename ... ArgPacks> 
template <typename ... APs> 
void TypeMe<ArgPacks...>::cycleAPs() 
{ 
    int _[] = {0, (cycleAP<APs>(), 0)...}; 
    (void)_; 
    return ; 
} 

template <typename ... ArgPacks> 
template <typename AP> 
void TypeMe<ArgPacks...>::cycleAP() 
{ 
    printf("SomeEnum = %d, Val = %d\n", static_cast<int>(AP::val_se), AP::val); 
    return ; 
} 

enum SomeEnum 
{ 
    A_SE, 
    B_SE, 
    C_SE, 
    MAX 
}; 

template <SomeEnum _se, int _val> 
struct Pack 
{ 
    enum {val_se = _se}; 
    enum {val = _val}; 
}; 

int main() 
{ 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<C_SE, 3>> tm_abc; // OK 
// TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<A_SE, 3>> tm_aba; // Should fail (first and last Pack are templated with A_SE) 

    (void)tm_abc; 
// (void)tm_aba; 
    return (0); 
} 
+1

"C++ 0x" n'est pas * vraiment * une chose, il était juste un nom de travail pour 11 C++. –

+0

ouais je n'étais pas sûr de celui-ci:/mais un de ma plate-forme cible doit être compilé avec -std = C++ 0x –

+1

C'est un indicateur pour le support C++ 11 incomplet, alors attendez-vous à une rupture aléatoire si vous allez la route C++ 11. Par exemple, la sémantique du mouvement des flux ne fonctionnera probablement pas. –

Répondre

2

Vous pouvez résoudre ce problème récursive:

Compte tenu des types (T1, T2, T3, ...., Tn)

  1. T1::value != T2::value doit être vrai
  2. T1::value != Ti::value doit être vrai pour i = 3, ..., n
  3. T2::value != Ti::value doit être vrai pour i = 3, ..., n

Dans le code , vous pouvez le faire comme ceci:

#include <type_traits> 

template <typename ...Ts> 
struct are_mutually_different; 

template <typename T> 
struct are_mutually_different<T> 
{ 
    static const bool value = true; 
}; 

template <typename T1, typename T2, typename ...Ts> 
struct are_mutually_different<T1, T2, Ts...> 
{ 
    static const bool value = (T1::value != T2::value) && 
          are_mutually_different<T1, Ts...>::value && 
          are_mutually_different<T2, Ts...>::value; 
}; 



void test() 
{ 
    using _1 = std::integral_constant<int, 1>; 
    using _2 = std::integral_constant<int, 2>; 
    using _3 = std::integral_constant<int, 3>; 
    using _4 = std::integral_constant<int, 4>; 
    using _5 = std::integral_constant<int, 5>; 

    static_assert(are_mutually_different<_1, _2, _3, _4>::value, ":("); 
    static_assert(!are_mutually_different<_1, _1, _3, _4>::value, ":("); 
    static_assert(!are_mutually_different<_1, _2, _1, _4>::value, ":("); 
    static_assert(!are_mutually_different<_1, _2, _3, _2>::value, ":("); 
} 
2

en espérant que quelqu'un d'autre peut montrer une solution plus élégante et plus simple, je propose l'insertion d'un static_assert() dans TypeMe et d l'élaboration à l'aide d'un ensemble de caractères spécifiques (allDifferentEnums) et génériques (allDiffs et fistDiffs).

Ce qui suit est un exemple simplifié mais compilable

#include <type_traits> 

enum SomeEnum 
{ A_SE, B_SE, C_SE, MAX }; 

template <SomeEnum _se, int _val> 
struct Pack 
{ }; 

template <typename T, T ... ts> 
struct firstDiffs; 

template <typename T, T t> 
struct firstDiffs<T, t> : std::true_type 
{ }; 

template <typename T, T t, T ... ts> 
struct firstDiffs<T, t, t, ts...> : std::false_type 
{ }; 

template <typename T, T t, T t0, T ... ts> 
struct firstDiffs<T, t, t0, ts...> : firstDiffs<T, t, ts...> 
{ }; 

template <typename T, T ... ts> 
struct allDiffs; 

template <typename T> 
struct allDiffs<T> : std::true_type 
{ }; 

template <typename T, T t, T ... ts> 
struct allDiffs<T, t, ts...> 
    : std::integral_constant<bool, firstDiffs<T, t, ts...>::value && 
            allDiffs<T, ts...>::value> 
{ }; 

template <typename...> 
struct allDifferentEnums: std::false_type 
{ }; 

template <SomeEnum ... ses, int ... vals> 
struct allDifferentEnums<Pack<ses, vals>...> : allDiffs<SomeEnum, ses...> 
{ }; 

template <typename ... ArgPacks> 
class TypeMe 
{ static_assert(allDifferentEnums<ArgPacks...>::value, "!"); }; 

int main() 
{ 
    // OK 
    TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<C_SE, 3>> tm_abc; 

    // static_assert failed "!" 
    // TypeMe<Pack<A_SE, 1>, Pack<B_SE, 2>, Pack<A_SE, 3>> tm_aba; 

    (void)tm_abc; 
    // (void)tm_aba; 
} 
+0

merci, cela fonctionne, mais la réponse @MadScientist est plus courte et j'ai moins de difficulté à la comprendre –