Espacios de nombres
Variantes
Acciones

std::void_t

De cppreference.com
< cpp‎ | types
 
 
Biblioteca de metaprogramación
Rasgos de tipo
Categorías de tipo
(C++11)
(C++11)(DR*)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11) 
(C++11)
(C++11)
Propiedades de tipos
(C++11)
(C++11)
(C++14)
(C++11)(en desuso en C++26)
(C++11)(hasta C++20*)
(C++11)(en desuso en C++20)
(C++11)
Constantes de rasgos de tipo
Metafunciones
(C++17)
Operaciones admitidas
Relaciones y consultas de propiedades
Modificaciones de tipos
(C++11)(C++11)(C++11)
Transformaciones de tipos
(C++11)(en desuso en C++23)
(C++11)(en desuso en C++23)
(C++11)
(C++11)(hasta C++20*)(C++17)

(C++11)
void_t
(C++17)
Aritmética racional en tiempo de compilación
Secuencias de enteros en tiempo de compilación
 
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) [editar]