C++-Standardvorlagen (STL) – Typunterstützung (verschiedene Transformationen, Ableitung des Ergebnistyps eines aufrufbaren Objekts mit einer Reihe von Argumenten, std::result_of, std::invoke_result)

Typeigenschaften

Ein Typattribut definiert eine vorlagenbasierte Struktur zur Kompilierungszeit zum Abfragen oder Ändern der Eigenschaften eines Typs.

Der Versuch, eine im Header <type_traits> definierte Vorlage zu spezialisieren, führt zu undefiniertem Verhalten, mit der Ausnahme, dass std::common_type wie beschrieben spezialisiert werden kann.

In der Header-Datei <type_traits> definierte Vorlagen können mit unvollständigen Typen instanziiert werden, sofern nicht anders angegeben, obwohl die Instanziierung von Standardbibliotheksvorlagen mit unvollständigen Typen generell verboten ist.
 

Verschiedene Transformationen

Leitet den Ergebnistyp des Aufrufs eines aufrufbaren Objekts mit einer Reihe von Argumenten ab

std::result_of, 
std::invoke_result
Vorlage< Klasse >

class result_of; // 不定义

template< Klasse F, Klasse... ArgTypes >

Klasse result_of<F(ArgTypes...)>;
(1) (C++11-Ursprung)
(C++17-Zwischenverwendung)
(C++20-Zwischenentfernung)

Vorlage< Klasse F, Klasse... ArgTypes>
class invoke_result;

(2) (seit C++17)

Der Rückgabetyp eines INVOKE-Ausdrucks wird zur Kompilierungszeit abgeleitet.

F muss ein aufrufbarer Typ, ein Verweis auf eine Funktion oder ein Verweis auf einen aufrufbaren Typ sein. Der Aufruf von mit ArgTypes... muss ein wohlgeformter Ausdruck sein. F (seit C++11)
FAlle Typen in und ArgTypes können ein beliebiger vollständiger Typ, ein Array mit unbekannten Grenzen oder (kann cv-qualifiziert sein) seinvoid (seit C++14)

Mitgliedstyp

Mitgliedstyp Definition
type Bei Aufruf mit ParameternAufrufbar (Aufrufbarer) Typ ist der Rückgabetyp. F ist nur definiert, wenn es in einem nicht ausgewerteten Kontext mit den Argumenten ArgTypes... aufgerufen werden kann. (seit C++14)ArgTypes...F

Hilfstyp

Vorlage< Klasse T >
mit result_of_t = typename result_of<T>::type;

(1) (C++14-Ursprung)
(C++17-Zwischenverwendung)
(C++20-Zwischenentfernung)

Vorlage< Klasse F, Klasse... ArgTypes>
using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;

(2) (seit C++17)

mögliche Umsetzung

namespace detail {
template <class T>
struct is_reference_wrapper : std::false_type {};
template <class U>
struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};
 
template <class Base, class T, class Derived, class... Args>
auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     std::is_base_of<Base, typename std::decay<Derived>::type>::value,
    decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))>::type;
 
template <class Base, class T, class RefWrap, class... Args>
auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
    decltype((ref.get().*pmf)(std::forward<Args>(args)...))>::type;
 
template <class Base, class T, class Pointer, class... Args>
auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args)
 -> typename std::enable_if<std::is_function<T>::value &&
                     !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
                     !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
    decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))>::type;
 
template <class Base, class T, class Derived>
auto INVOKE(T Base::*pmd, Derived&& ref)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     std::is_base_of<Base, typename std::decay<Derived>::type>::value,
    decltype(std::forward<Derived>(ref).*pmd)>::type;
 
template <class Base, class T, class RefWrap>
auto INVOKE(T Base::*pmd, RefWrap&& ref)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     is_reference_wrapper<typename std::decay<RefWrap>::type>::value,
    decltype(ref.get().*pmd)>::type;
 
template <class Base, class T, class Pointer>
auto INVOKE(T Base::*pmd, Pointer&& ptr)
 -> typename std::enable_if<!std::is_function<T>::value &&
                     !is_reference_wrapper<typename std::decay<Pointer>::type>::value &&
                     !std::is_base_of<Base, typename std::decay<Pointer>::type>::value,
    decltype((*std::forward<Pointer>(ptr)).*pmd)>::type;
 
template <class F, class... Args>
auto INVOKE(F&& f, Args&&... args)
 -> typename std::enable_if<!std::is_member_pointer<typename std::decay<F>::type>::value,
    decltype(std::forward<F>(f)(std::forward<Args>(args)...))>::type;
} // namespace detail
 
// 最小 C++11 实现:
template <class> struct result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)> {
    using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<ArgTypes>()...));
};
 
// 符合 C++14 的实现(亦为合法的 C++11 实现):
namespace detail {
template <typename AlwaysVoid, typename, typename...>
struct invoke_result { };
template <typename F, typename...Args>
struct invoke_result<decltype(void(detail::INVOKE(std::declval<F>(), std::declval<Args>()...))),
                 F, Args...> {
    using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<Args>()...));
};
} // namespace detail
 
template <class> struct result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)> : detail::invoke_result<void, F, ArgTypes...> {};
 
template <class F, class... ArgTypes>
struct invoke_result : detail::invoke_result<void, F, ArgTypes...> {};

 Ausgabe

#include <type_traits>
#include <iostream>

struct S
{
    double operator()(char, int&);
    float operator()(int)
    {
        return 1.0;
    }
};

template<class T>
typename std::result_of<T(int)>::type f(T& t)
{
    std::cout << "overload of f for callable T" << std::endl;
    return t(0);
}

template<class T, class U>
int f(U u)
{
    std::cout << "overload of f for non-callable T" << std::endl;
    return u;
}

int main()
{
    std::cout << std::boolalpha;
    // 以 char 和 int 参数调用 S 的结果是 double
    std::result_of<S(char, int&)>::type d = 3.14; // d 拥有 double 类型
    std::cout << "std::is_same<decltype(d), double>::value:     "
              << std::is_same<decltype(d), double>::value << std::endl;

    // 以 int 参数调用 S 的结果是 float
    std::result_of<S(int)>::type x = 3.14; // x 拥有 float 类型
    std::cout << "std::is_same<decltype(x), double>::value:     "
              << std::is_same<decltype(x), double>::value << std::endl;

    // result_of 能以指向成员函数的指针以如下方式使用
    struct C
    {
        double Func(char, int&);
    };
    std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
    std::cout << "std::is_same<decltype(g), double>::value:     "
              << std::is_same<decltype(g), double>::value << std::endl;

    f<C>(1); // C++11 中可能编译失败; C++14 中调用不可调用重载

    return 0;
}

Guess you like

Origin blog.csdn.net/qq_40788199/article/details/134795625