std::void_t
Definido en el archivo de encabezado <type_traits>
|
||
template< class... > using void_t = void; |
(desde C++17) | |
Metafunción de servicio que asigna una secuencia de cualquier tipo al tipo void. Esta metafunción es una forma conveniente de aprovechar los conceptos de SFINAE anteriores a C++20, en particular para eliminar condicionalmente funciones del conjunto de candidatos en función de si una expresión es válida en el contexto no evaluado (como operando para la expresión decltype), lo que permite que existan sobrecargas de funciones o especializaciones independientes en función de las operaciones admitidas.
[editar] Notas
Esta metafunción se usa en la metaprogramación de plantillas para detectar tipos malformados en un contexto SFINAE:
// plantilla primaria maneja tipos que no tienen un miembro anidado ::type: template<class, class = void> struct has_type_member : std::false_type {}; // especialización reconoce tipos que tienen un miembro anidado ::type: template<class T> struct has_type_member<T, std::void_t<typename T::type>> : std::true_type {};
También puede usarse para detectar la validez de una expresión:
// plantilla primaria maneja tipos que no admiten preincremento: template<class, class = void> struct has_pre_increment_member : std::false_type {}; // especialización reconoce tipos que admiten preincremento: template<class T> struct has_pre_increment_member<T, std::void_t<decltype( ++std::declval<T&>() )> > : std::true_type {};
Hasta la resolución de CWG issue 1558 (un defecto de C++11), los parámetros no utilizados en las plantillas de alias no estaban garantizados para asegurar SFINAE y podían ignorarse, por lo que los compiladores anteriores requieren una definición más compleja de void_t
, como
template<typename... Ts> struct make_void { typedef void type; }; template<typename... Ts> using void_t = typename make_void<Ts...>::type;
Macro de Prueba de característica | Valor | Estándar | Comentario |
---|---|---|---|
__cpp_lib_void_t |
201411L | (C++17) | std::void_t
|
[editar] Ejemplo
#include <iomanip> #include <iostream> #include <map> #include <type_traits> #include <vector> // Plantilla de variable que verifica si un tipo tiene funciones miembro begin() y end() template<typename, typename = void> constexpr bool is_iterable = false; template<typename T> constexpr bool is_iterable< T, std::void_t<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end()) > > = true; // Un rasgo de iterador cuyo value_type es el value_type del contenedor iterado, // admite incluso back_insert_iterator (donde el value_type es void) template<typename T, typename = void> struct iterator_trait : std::iterator_traits<T> {}; template<typename T> struct iterator_trait<T, std::void_t<typename T::container_type>> : std::iterator_traits<typename T::container_type::iterator> {}; class A {}; #define SHOW(...) std::cout << std::setw(34) << #__VA_ARGS__ \ << " == " << __VA_ARGS__ << '\n' int main() { std::cout << std::boolalpha << std::left; SHOW(is_iterable<std::vector<double>>); SHOW(is_iterable<std::map<int, double>>); SHOW(is_iterable<double>); SHOW(is_iterable<A>); using container_t = std::vector<int>; container_t v; static_assert(std::is_same_v< container_t::value_type, iterator_trait<decltype(std::begin(v))>::value_type >); static_assert(std::is_same_v< container_t::value_type, iterator_trait<decltype(std::back_inserter(v))>::value_type >); }
Salida:
is_iterable<std::vector<double>> == true is_iterable<std::map<int, double>> == true is_iterable<double> == false is_iterable<A> == false
[editar] Véase también
(C++11) |
Condicionalmente elimina una sobrecarga de función o especialización de plantilla de la resolución de sobrecargas. (plantilla de clase) |