c++ variadic-templates

c++ - ¿Cómo puedo verificar que el tipo T está entre el paquete de parámetros Ts...?



variadic-templates (4)

Compruebe si el tipo T está entre el paquete de parámetros Ts:

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

variable de plantilla.

Alternativa:

template<class T0, class... Ts> constexpr std::integral_constant<bool,(std::is_same<T0, Ts>{}||...)> is_one_of = {};

Que tiene diferencias sutiles.

Quiero escribir una función para devolver verdadero si T es uno de Ts...

template<class T, class... Ts> bool is_one_of<T, Ts...>();

Por ejemplo, is_one_of<int, double, int, float> devuelve true , y is_one_of<int, double, std::string, bool, bool> devuelve false .

Mi propia implementación es

template<class T1, class T2> bool is_one_of<T1, T2>() { return std::is_same<T1, T2>; } template<class T1, class T2, class... Ts> bool is_one_of<T1, T2, Ts...>() { if (std::is_same<T1, T2>) { return true; } else { return is_one_of<T1, Ts...>(); } }

Esta comprobación me parece común, así que me pregunto si ya existe una función de este tipo en la biblioteca estándar.


En su propia implementación, un problema es que C ++ no permite la especialización parcial en las plantillas de funciones.

Puede usar la expresión de plegado (que se introduce en C ++ 17) en lugar de la llamada a función recursiva.

template<class T1, class... Ts> constexpr bool is_one_of() noexcept { return (std::is_same_v<T1, Ts> || ...); }

Si está utilizando C ++ 11 donde fold expression y std::disjunction no están disponibles, puede implementar is_one_of esta forma:

template<class...> struct is_one_of: std::false_type {}; template<class T1, class T2> struct is_one_of<T1, T2>: std::is_same<T1, T2> {}; template<class T1, class T2, class... Ts> struct is_one_of<T1, T2, Ts...>: std::conditional<std::is_same<T1, T2>::value, std::is_same<T1, T2>, is_one_of<T1, Ts...>>::type {};


Las otras respuestas muestran varias soluciones correctas para resolver este problema específico de una manera limpia y concisa. Aquí hay una solución que no se recomienda para este problema específico , pero que demuestra una técnica alternativa: en constexpr funciones constexpr puede usar los bucles y la lógica simple para calcular los resultados en el momento de la compilación. Esto permite deshacerse de la recursión y el intento de especialización de plantilla parcial del código de OP.

#include <initializer_list> #include <type_traits> template<class T, class... Ts> constexpr bool is_one_of() { bool ret = false; for(bool is_this_one : {std::is_same<T, Ts>::value...}) { ret |= is_this_one;// alternative style: `if(is_this_one) return true;` } return ret; } static_assert(is_one_of<int, double, int, float>(), ""); static_assert(!is_one_of<int, double, char, bool, bool>(), "");

Requiere al menos C ++ 14 .


También puede usar std::disjunction para evitar la creación innecesaria de instancias de plantillas:

template <class T0, class... Ts> constexpr bool is_one_of = std::disjunction_v<std::is_same<T0, Ts>...>;

Una vez que se encuentra un tipo coincidente, las plantillas restantes no se crean instancias. En contraste, una expresión de doblez crea una instancia de todos ellos. Esto puede hacer una diferencia significativa en el tiempo de compilación dependiendo de su caso de uso.