2013-06-10 13 views
24

Come posso creare un modello di classe che restituisce se uno qualsiasi dei suoi tipi variadici è uguale al primo tipo. Voglio essere in grado di fare questo:Come fare a variadic is_same?

is_same<T, A, B, C>::value; // true if T is one of A, B or C 

E se T è uguale a uno qualsiasi di questi tipi, la sua statica value membro sarà true, altrimenti false. Come posso fare questo?

+3

Dal momento che il vostro intento non era chiaro (due persone hanno fatto la stessa interpretazione sbagliata) Mi sono permesso di riformulare leggermente la tua domanda. – syam

risposta

30

Usa modello ricorsione:

template<typename T, typename... Rest> 
struct is_any : std::false_type {}; 

template<typename T, typename First> 
struct is_any<T, First> : std::is_same<T, First> {}; 

template<typename T, typename First, typename... Rest> 
struct is_any<T, First, Rest...> 
    : std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value> 
{}; 

static_assert(is_any<int, char, double, int>::value, "error 1"); // OK 
static_assert(is_any<int, char, double, short>::value, "error 2"); // error 
+0

Grazie a questo ha funzionato. :) –

7

Qualcosa di simile. In primo luogo, una piccola biblioteca metaprogrammazione, perché aggiunge come 2 linee di farlo genericamente:

template<template<typename,typename>class checker, typename... Ts> 
struct is_any_to_first : std::false_type {}; 

template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts> 
struct is_any_to_first<checker, T0, T1, Ts...> : 
    std::integral_constant< bool, checker<T0, T1>::value || is_any_to_first<checker, T0, Ts...>::value> 
{}; 

Poi un'implementazione 2 linea di is_any_same_to_first:

template<typename... Ts> 
using is_any_same_to_first = is_any_to_first< std::is_same, Ts... >; 

E per completezza, l'originale is_all, che può anche rivelarsi utile:

template<template<typename,typename>class checker, typename... Ts> 
struct is_all : std::true_type {}; 

template<template<typename,typename>class checker, typename T0, typename T1, typename... Ts> 
struct is_all<checker, T0, T1, Ts...> : 
    std::integral_constant< bool, checker<T0, T1>::value && is_all<checker, T0, Ts...>::value> 
{}; 

template<typename... Ts> 
using is_all_same = is_all< std::is_same, Ts... >; 

Live example del is_all_same.

Nota che chiamare il numero is_any_same_to_first in modo meno esplicito è un problema. 2/3 persone che hanno provato a rispondere a questa domanda, incluso me, hanno supposto che is_same<A,B,C> sia vero se tutte e tre sono dello stesso tipo!

+0

Hmm Vedo che hai preso l'altra decisione rispetto a me ('is_all_same' invece di' is_any'). A dire il vero, ho esitato a chiedere a OP chiarimenti al riguardo. – syam

+0

Um ... Questo codice funzionerà solo se * tutti * i tipi sono gli stessi. Sto cercando se 'T' è * o *' A', 'B' o' C'. –

2

Utilizzando le rilassate C++ 14 funzioni constexpr, questo tipo di cose sono molto più facili da codice, e probabilmente molto più veloce per compilare e, in modo si potrebbe scrivere:

template <class T, class ... Candidates> 
constexpr bool is_all_same() { 
    bool pairs[] = {std::is_same_v<T,Candidates>...}; 
    for(bool p: pairs) if(!p) return false; 
    return true; 
} 

template <class T, class ... Candidates> 
constexpr bool is_any_same() { 
    bool pairs[] = {std::is_same_v<T,Candidates>...}; 
    for(bool p: pairs) if(p) return true; 
    return false; 
} 

Ciò è reso possibile dal fatto che in C++ 14 le funzioni di constexpr possono avere cicli.

10

Nizza e conciso con C++ 17:

template <class T, class... Ts> 
struct is_any : std::disjunction<std::is_same<T, Ts>...> {}; 

e il doppio:

template <class T, class... Ts> 
struct are_same : std::conjunction<std::is_same<T, Ts>...> {}; 

Una variante che usa piegare le espressioni:

template <class T, class... Ts> 
struct is_any : std::bool_constant<(std::is_same_v<T, Ts> || ...)> {}; 

template <class T, class... Ts> 
struct are_same : std::bool_constant<(std::is_same_v<T, Ts> && ...)> {};