Namespaces
Variants

std:: result_of, std:: invoke_result

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)
result_of invoke_result
(C++11) ( until C++20* ) (C++17)

Compile-time rational arithmetic
Compile-time integer sequences
Défini dans l'en-tête <type_traits>
template < class >

class result_of ; // non défini

template < class F, class ... ArgTypes >

class result_of < F ( ArgTypes... ) > ;
(1) (depuis C++11)
(déprécié en C++17)
(supprimé en C++20)
template < class F, class ... ArgTypes >
class invoke_result ;
(2) (depuis C++17)

Déduit le type de retour d'une INVOKE expression au moment de la compilation.

F doit être un type appelable, une référence à une fonction, ou une référence à un type appelable. L'invocation de F avec ArgTypes... doit être une expression bien formée.

(depuis C++11)
(jusqu'à C++14)

F et tous les types dans ArgTypes peuvent être n'importe quel type complet, tableau de limite inconnue, ou void (éventuellement qualifié cv).

(depuis C++14)

Si le programme ajoute des spécialisations pour l'un des modèles décrits sur cette page, le comportement est indéfini.

Table des matières

Types membres

Type de membre Définition
type le type de retour du type Callable F s'il est invoqué avec les arguments ArgTypes... . Défini uniquement si F peut être appelé avec les arguments ArgTypes... dans un contexte non évalué. (depuis C++14)

Types auxiliaires

template < class T >
using result_of_t = typename result_of < T > :: type ;
(1) (depuis C++14)
(obsolète en C++17)
(supprimé en C++20)
template < class F, class ... ArgTypes >
using invoke_result_t = typename invoke_result < F, ArgTypes... > :: type ;
(2) (depuis C++17)

Implémentation possible

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 T>
    struct invoke_impl
    {
        template<class F, class... Args>
        static auto call(F&& f, Args&&... args)
            -> decltype(std::forward<F>(f)(std::forward<Args>(args)...));
    };
    template<class B, class MT>
    struct invoke_impl<MT B::*>
    {
        template<class T, class Td = typename std::decay<T>::type,
            class = typename std::enable_if<std::is_base_of<B, Td>::value>::type>
        static auto get(T&& t) -> T&&;
        template<class T, class Td = typename std::decay<T>::type,
            class = typename std::enable_if<is_reference_wrapper<Td>::value>::type>
        static auto get(T&& t) -> decltype(t.get());
        template<class T, class Td = typename std::decay<T>::type,
            class = typename std::enable_if<!std::is_base_of<B, Td>::value>::type,
            class = typename std::enable_if<!is_reference_wrapper<Td>::value>::type>
        static auto get(T&& t) -> decltype(*std::forward<T>(t));
        template<class T, class... Args, class MT1,
            class = typename std::enable_if<std::is_function<MT1>::value>::type>
        static auto call(MT1 B::*pmf, T&& t, Args&&... args)
            -> decltype((invoke_impl::obtenir(
                std::forward<T>(t)).*pmf)(std::forward<Args>(args)...));
        template<class T>
        static auto call(MT B::*pmd, T&& t)
            -> decltype(invoke_impl::obtenir(std::forward<T>(t)).*pmd);
    };
    template<class F, class... Args, class Fd = typename std::decay<F>::type>
    auto INVOKE(F&& f, Args&&... args)
        -> decltype(invoke_impl<Fd>::appel(std::forward<F>(f),
            std::forward<Args>(args)...));
} // namespace detail
// Implémentation minimale C++11 :
template<class> struct result_of;
template<class F, class... ArgTypes>
struct result_of<F(ArgTypes...)>
{
    using type = decltype(detail::INVOKER(std::declval<F>(), std::declval<ArgTypes>()...));
};
// Implémentation conforme C++14 (est également une implémentation C++11 valide) :
namespace detail
{
    template<typename AlwaysVoid, typename, typename...>
    struct invoke_result {};
    template<typename F, typename...Args>
    struct invoke_result<
        decltype(void(detail::INVOKER(std::declval<F>(), std::declval<Args>()...))),
            F, Args...>
    {
        using type = decltype(detail::INVOKER(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...> {};

Notes

Comme formulé dans C++11, le comportement de std::result_of est indéfini lorsque INVOKE(std::declval<F>(), std::declval<ArgTypes>()...) est mal formé (par exemple lorsque F n'est pas du tout un type appelable). C++14 modifie cela en un SFINAE (lorsque F n'est pas appelable, std::result_of<F(ArgTypes...)> n'a simplement pas le membre type ).

La motivation derrière std::result_of est de déterminer le résultat de l'invocation d'un Callable , en particulier si ce type de résultat diffère pour différents ensembles d'arguments.

F ( Args... ) est un type de fonction où Args... représente les types d'arguments et F le type de retour. De ce fait, std::result_of présente plusieurs particularités qui ont conduit à son dépréciation au profit de std::invoke_result dans C++17 :

  • F ne peut pas être un type fonction ou un type tableau (mais peut être une référence vers ceux-ci) ;
  • si l'un des Args a le type "tableau de T " ou un type fonction T , il est automatiquement ajusté en T* ;
  • ni F ni aucun des Args... ne peut être un type classe abstraite ;
  • si l'un des Args... possède un qualificatif cv de plus haut niveau, il est ignoré ;
  • aucun des Args... ne peut être de type void .

Pour éviter ces particularités, result_of est souvent utilisé avec des types référence comme F et Args... . Par exemple :

template<class F, class... Args>
std::result_of_t<F&&(Args&&...)> // au lieu de std::result_of_t<F(Args...)>, qui est incorrect
    my_invoke(F&& f, Args&&... args)
    {
        /* implémentation */
    }

Notes

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_lib_result_of_sfinae 201210L (C++14) std::result_of et SFINAE
__cpp_lib_is_invocable 201703L (C++17) std::is_invocable , std::invoke_result

Exemples

#include <iostream>
#include <type_traits>
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\n";
    return t(0);
}
template<class T, class U>
int f(U u)
{
    std::cout << "overload of f for non-callable T\n";
    return u;
}
int main()
{
    // le résultat de l'appel de S avec des arguments char et int& est double
    std::result_of<S(char, int&)>::type d = 3.14; // d a le type double
    static_assert(std::is_same<decltype(d), double>::value, "");
    // std::invoke_result utilise une syntaxe différente (sans parenthèses)
    std::invoke_result<S,char,int&>::type b = 3.14;
    static_assert(std::is_same<decltype(b), double>::value, "");
    // le résultat de l'appel de S avec un argument int est float
    std::result_of<S(int)>::type x = 3.14; // x a le type float
    static_assert(std::is_same<decltype(x), float>::value, "");
    // result_of peut être utilisé avec un pointeur vers une fonction membre comme suit
    struct C { double Func(char, int&); };
    std::result_of<decltype(&C::Func)(C, char, int&)>::type g = 3.14;
    static_assert(std::is_same<decltype(g), double>::value, "");
    f<C>(1); // peut échouer à compiler en C++11 ; appelle la surcharge non-appelable en C++14
}

Sortie :

overload of f for non-callable T

Voir aussi

(C++17) (C++23)
invoque tout Callable objet avec les arguments donnés et possibilité de spécifier le type de retour (depuis C++23)
(modèle de fonction)
vérifie si un type peut être invoqué (comme par std::invoke ) avec les types d'arguments donnés
(modèle de classe)
(C++11)
obtient une référence à un objet du type template pour utilisation dans un contexte non évalué
(modèle de fonction)