Namensräume
Varianten
Aktionen

std::void_t

Von cppreference.com
< cpp‎ | types
 
 
Metaprogrammierungsbibliothek
Typmerkmale
Typkategorien
(C++11)
(C++11)(DR*)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11) 
(C++11)
(C++11)
Typeneigenschaften
(C++11)
(C++11)
(C++14)
(C++11)(deprecated in C++26)
(C++11)(bis C++20*)
(C++11)(veraltet in C++20)
(C++11)
Typmerkmalskonstanten
Metafunktionen
(C++17)
Unterstützte Operationen
Beziehungen und Eigenschaftsabfragen
Typmodifikationen
(C++11)(C++11)(C++11)
Typentransformationen
(C++11)(veraltet in C++23)
(C++11)(veraltet in C++23)
(C++11)
(C++11)(bis C++20*)(C++17)

(C++11)
(C++11)
void_t
(C++17)
Rationale Arithmetik zur Compilezeit
Ganzzahlsequenzen zur Compilezeit
 
Definiert in der Kopfdatei <type_traits>
template< class... >
using void_t = void;
(seit C++17)

Metafunktion, die eine Sequenz von beliebigen Typen auf den Typ void abbildet. Diese Metafunktion ist eine bequeme Möglichkeit, SFINAE vor den Konzepten von C++20 zu nutzen, insbesondere um Funktionen bedingt aus der Menge der Kandidaten zu entfernen, basierend darauf, ob ein Ausdruck im unevaluierten Kontext (wie z.B. ein Operand eines decltype-Ausdrucks) gültig ist. Dies ermöglicht das Vorhandensein separater Funktionsüberladungen oder Spezialisierungen basierend auf unterstützten Operationen.

[bearbeiten] Hinweise

Diese Metafunktion wird in der Template-Metaprogrammierung verwendet, um fehlerhafte Typen im SFINAE-Kontext zu erkennen.

// primary template handles types that have no nested ::type member:
template<class, class = void>
struct has_type_member : std::false_type {};
 
// specialization recognizes types that do have a nested ::type member:
template<class T>
struct has_type_member<T, std::void_t<typename T::type>> : std::true_type {};

Sie kann auch zur Erkennung der Gültigkeit eines Ausdrucks verwendet werden.

// primary template handles types that do not support pre-increment:
template<class, class = void>
struct has_pre_increment_member : std::false_type {};
 
// specialization recognizes types that do support pre-increment:
template<class T>
struct has_pre_increment_member<T,
           std::void_t<decltype( ++std::declval<T&>() )>
       > : std::true_type {};

Bis zur Lösung des CWG-Problems 1558 (ein Fehler in C++11) war nicht garantiert, dass unbenutzte Parameter in Alias-Templates SFINAE sicherstellten und ignoriert werden konnten. Daher erforderten frühere Compiler eine komplexere Definition von void_t, wie z.B.:

template<typename... Ts>
struct make_void { typedef void type; };
 
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
Feature-Test-Makro Wert Std Feature
__cpp_lib_void_t 201411L (C++17) std::void_t

[bearbeiten] Beispiel

#include <iomanip>
#include <iostream>
#include <map>
#include <type_traits>
#include <vector>
 
// Variable template that checks if a type has begin() and end() member functions
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;
 
// An iterator trait those value_type is the value_type of the iterated container,
// supports even back_insert_iterator (where value_type is 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
    >);
}

Ausgabe

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

[bearbeiten] Siehe auch

(C++11)
entfernt bedingt eine Funktionsüberladung oder Template-Spezialisierung aus der Überladungsauflösung
(Klassenvorlage) [bearbeiten]