10

Si tratta di un frammento di codice che ho intenzione di utilizzare al fine di verificare se i tipi di modello variadic sono uniche:Come posso rendere più breve questo codice di template variadic utilizzando le funzionalità di C++ 14 e C++ 1z?

template <typename...> 
struct is_one_of; 

template <typename F> 
struct is_one_of<F> { 
    static constexpr bool value = false; 
}; 

template <typename F, typename S, typename... T> 
struct is_one_of<F, S, T...> { 
    static constexpr bool value = 
     std::is_same<F, S>::value || is_one_of<F, T...>::value; 
}; 

template <typename...> 
struct is_unique; 

template <> 
struct is_unique<> { 
    static constexpr bool value = true; 
}; 

template <typename F, typename... T> 
struct is_unique<F, T...> { 
    static constexpr bool value = 
     is_unique<T...>::value && !is_one_of<F, T...>::value; 
}; 

int main() { 
    constexpr bool b = is_unique<bool, int, double>::value; 
    constexpr bool c = is_unique<int, char, int>::value; 
    static_assert(b == true && c == false, "!"); 
} 

C'è un modo per rendere il codice più corti e/o più concise funzioni utilizzando introdotte nel C++ 14 e C++ 1z? O c'è un modo migliore per ottenere lo stesso effetto usando le nuove funzionalità?

Nel caso di C++ 1z, intendo: funzionalità che sono già disponibili nelle versioni più recenti di Clang e GCC.

+0

No, è abbastanza conciso così com'è. Quando vengono introdotte le espressioni di piegatura, tuttavia, puoi fare qualcosa del tipo: 'constexpr statico valore bool = std :: is_same :: valore || ... ' –

+1

@BrianRodriguez: Penso che abbia bisogno di parentesi tonde. –

+0

Puoi usare un po 'di trucchetti per rendere 'is_one_of' un po' più conciso: http://coliru.stacked-crooked.com/a/3b9755f28193a13b – melak47

risposta

6
#include <type_traits> 

template <typename F, typename... Ts> 
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...); 

template <typename...> 
constexpr bool is_unique = true; 

template <typename F, typename... Ts> 
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>; 

DEMO

3

mi piacerebbe (ora) consiglia di utilizzare l'std::conj/disj/nega famiglia di funzioni STL:

#include <type_traits> 

template <typename H, typename... T> 
struct is_one_of : std::disjunction<std::is_same<H, T>...> {}; 

template <typename H, typename... T> 
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {}; 

template <typename H> 
struct is_unique<H> : std::true_type {}; 

int main() 
{ 
    static_assert(is_one_of<int, char, double, int, bool>::value); 
    static_assert(is_unique<int, char, double, bool>::value); 
    static_assert(!is_unique<int, int, char, double, bool>::value); 
} 

Quando fold-expressions, che sono stati progettati per questi casi, vengono rilasciati nella lingua Questo diventerà banale:

namespace stx = std::experimental; 

template <typename H, typename... T> 
struct is_one_of { 
    static constexpr bool value = (stx::is_same_v<H, T> || ...); 
}; 

template <typename H, typename... T> 
struct is_unique { 
    static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value); 
}; 

template <typename H> 
struct is_unique<H> : std::true_type {}; 
+0

Il tuo 'is_unique' controlla solo se' H' è univoco, ma altri 'T's potrebbero ancora avere duplicati nella lista dei tipi. – melak47

+1

Questo codice non ha possibilità di compilare –

+0

Questo codice è rotto in così tanti modi diversi che è chiaro che non è mai stato nemmeno minimamente testato. –

2

Sono in linea con le risposte di Brian Rodriguez e Piotr Scontnincki, per quanto riguarda la parte delle espressioni di piegatura. Fino a quando le espressioni pieghevoli sono, si potrebbe ridursi il codice esistente un po 'per sbarazzarsi dei modelli primari incompleti come segue:

template <typename...> 
struct is_one_of { 
    static constexpr bool value = false; 
}; 

template <typename F, typename S, typename... T> 
struct is_one_of<F, S, T...> { 
    static constexpr bool value = 
     std::is_same<F, S>::value || is_one_of<F, T...>::value; 
}; 

template <typename...> 
struct is_unique { 
    static constexpr bool value = true; 
}; 

template <typename F, typename... T> 
struct is_unique<F, T...> { 
    static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value; 
}; 
9

Recentemente abbiamo aggiunto std::disjunction al C++ 1z progetto, che può essere utilizzato per la is_one_of (e si ferma istanziare non appena viene trovata una corrispondenza, vedere il link per maggiori informazioni):

template <typename F, typename... T> 
    using is_one_of = std::disjunction<is_same<F, T>...>; 

Questo è già implementato nel trunk GCC. Per le versioni più vecchie di GCC è possibile utilizzare il dettaglio di implementazione __or_ invece:

template <typename F, typename... T> 
    using is_one_of = std::__or_<is_same<F, T>...>; 

o implementare disjunction a mano utilizzando C++ 11 strutture, come mostrato alla fine della proposta linkato sopra.

+0

È fantastico !!! – 101010

Problemi correlati