Namespaces
Variants

std:: void_t

From cppreference.net
Metaprogramming library
Type traits
Type categories
(C++11)
(C++11) ( DR* )
Type properties
(C++11)
(C++11)
(C++14)
(C++11) (deprecated in C++26)
(C++11) ( until C++20* )
(C++11) (deprecated in C++20)
(C++11)
Type trait constants
Metafunctions
(C++17)
Supported operations
Relationships and property queries
Type modifications
Type transformations
(C++11) (deprecated in C++23)
(C++11) (deprecated in C++23)
(C++11)
(C++11) ( until C++20* ) (C++17)

(C++11)
void_t
(C++17)
Compile-time rational arithmetic
Compile-time integer sequences
Definido en el encabezado <type_traits>
template < class ... >
using void_t = void ;
(desde C++17)

Metafunción de utilidad que mapea una secuencia de cualquier tipo al tipo void . Esta metafunción es una forma conveniente de aprovechar SFINAE antes de los conceptos de C++20, en particular para eliminar condicionalmente funciones del conjunto de candidatos basándose en si una expresión es válida en el contexto no evaluado (como operando de una expresión decltype ), permitiendo que existan sobrecargas de funciones o especializaciones separadas basadas en operaciones soportadas.

Notas

Esta metafunción se utiliza en metaprogramación de plantillas para detectar tipos mal formados en contexto SFINAE:

// la plantilla principal maneja tipos que no tienen un miembro ::type anidado:
template<class, class = void>
struct has_type_member : std::false_type {};
// la especialización reconoce tipos que sí tienen un miembro ::type anidado:
template<class T>
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type {};

También puede utilizarse para detectar la validez de una expresión:

// la plantilla primaria maneja tipos que no admiten pre-incremento:
template<class, class = void>
struct has_pre_increment_member : std::false_type {};
// la especialización reconoce tipos que sí admiten pre-incremento:
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 alias templates no garantizaban SFINAE y podían ser ignorados, 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ísticas Valor Estándar Característica
__cpp_lib_void_t 201411L (C++17) std::void_t

Ejemplo

#include <iomanip>
#include <iostream>
#include <map>
#include <type_traits>
#include <vector>
// Variable template que verifica si un tipo tiene funciones miembro begin() y end()
template<typename, typename = void>
constexpr bool is_range = false;
template<typename T>
constexpr bool is_range<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 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_range<std::vector<double>>);
    SHOW(is_range<std::map<int, double>>);
    SHOW(is_range<double>);
    SHOW(is_range<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_range<std::vector<double>>   == true
is_range<std::map<int, double>> == true
is_range<double>                == false
is_range<A>                     == false

Véase también

(C++11)
elimina condicionalmente una sobrecarga de función o especialización de plantilla de la resolución de sobrecarga
(plantilla de clase)