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
Défini dans l'en-tête <type_traits>
template < class ... >
using void_t = void ;
(depuis C++17)

Métafonction utilitaire qui transforme une séquence de types quelconques en le type void . Cette métafonction est un moyen pratique d'exploiter SFINAE avant les concepts de C++20, en particulier pour supprimer conditionnellement des fonctions de l' ensemble des candidats selon qu'une expression est valide dans le contexte non évalué (tel qu'un opérande d'une expression decltype ), permettant ainsi l'existence de surcharges de fonctions ou de spécialisations distinctes basées sur les opérations supportées.

Notes

Cette métafonction est utilisée en métaprogrammation de modèles pour détecter les types mal formés dans un contexte SFINAE :

// le modèle primaire gère les types qui n'ont pas de membre ::type imbriqué :
template<class, class = void>
struct has_type_member : std::false_type {};
// la spécialisation reconnaît les types qui ont un membre ::type imbriqué :
template<class T>
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type {};

Il peut également être utilisé pour détecter la validité d'une expression :

// le modèle principal gère les types qui ne supportent pas le pré-incrément :
template<class, class = void>
struct has_pre_increment_member : std::false_type {};
// la spécialisation reconnaît les types qui supportent le pré-incrément :
template<class T>
struct has_pre_increment_member<T,
           std::void_t<decltype(++std::declval<T&>())>
       > : std::true_type {};

Jusqu'à la résolution de CWG issue 1558 (un défaut de C++11), les paramètres inutilisés dans les alias templates n'étaient pas garantis d'assurer SFINAE et pouvaient être ignorés, donc les compilateurs antérieurs nécessitent une définition plus complexe de void_t , telle que

template<typename... Ts>
struct make_void { typedef void type; };
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_lib_void_t 201411L (C++17) std::void_t

Exemple

#include <iomanip>
#include <iostream>
#include <map>
#include <type_traits>
#include <vector>
// Variable template qui vérifie si un type possède des fonctions membres begin() et 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 trait d'itérateur dont le value_type est le value_type du conteneur itéré,
// prend en charge même back_insert_iterator (où value_type est 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>);
}

Sortie :

is_range<std::vector<double>>   == true
is_range<std::map<int, double>> == true
is_range<double>                == false
is_range<A>                     == false

Voir aussi

(C++11)
supprime conditionnellement une surcharge de fonction ou une spécialisation de modèle de la résolution de surcharge
(modèle de classe)