名前空間
変種
操作

std::result_of, std::invoke_result

From cppreference.com
< cpp‎ | types
 
 
メタプログラミングライブラリ
型特性
型のカテゴリ
(C++11)
(C++11)(DR*)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11)
(C++11) 
(C++11)
(C++11)
型のプロパティ
(C++11)
(C++11)
(C++14)
(C++11)(C++26で非推奨)
(C++11)(C++20まで*)
(C++11)(C++20で非推奨)
(C++11)
型特性定数
メタ関数
(C++17)
サポートされている操作
関係とプロパティクエリ
型の変更
(C++11)(C++11)(C++11)
型の変換
(C++11)(C++23で非推奨)
(C++11)(C++23で非推奨)
(C++11)
result_ofinvoke_result
(C++11)(C++20まで*)(C++17)

(C++11)
(C++17)
コンパイル時有理数演算
コンパイル時整数シーケンス
 
ヘッダ <type_traits> で定義
template< class >

class result_of; // 未定義

template< class F, class... ArgTypes >

class result_of<F(ArgTypes...)>;
(1) (C++11以降)
(C++17で非推奨)
(C++20で削除)
template< class F, class... ArgTypes >
class invoke_result;
(2) (C++17以降)

コンパイル時にINVOKEの戻り値を推論します。

Fは呼び出し可能な型、関数への参照、または呼び出し可能な型への参照である必要があります。FArgTypes...で呼び出す式は整形式でなければなりません。

(C++11以降)
(C++14まで)

FArgTypesのすべての型は、完全な型、未知境界の配列、または(cv修飾された可能性のある)voidのいずれかになります。

(C++14以降)

プログラムがこのページで説明されているテンプレートのいずれかに特殊化を追加する場合、動作は未定義です。

目次

[編集] メンバ型

メンバ型 定義
type CallableFを引数ArgTypes...で呼び出した場合の戻り値の型。Fが未評価のコンテキストで引数ArgTypes...で呼び出し可能な場合にのみ定義されます。(C++14以降)

[編集] ヘルパー型

template< class T >
using result_of_t = typename result_of<T>::type;
(1) (C++14以降)
(C++17で非推奨)
(C++20で削除)
template< class F, class... ArgTypes >
using invoke_result_t = typename invoke_result<F, ArgTypes...>::type;
(2) (C++17以降)

[編集] 可能な実装

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::get(
                std::forward<T>(t)).*pmf)(std::forward<Args>(args)...));
 
        template<class T>
        static auto call(MT B::*pmd, T&& t)
            -> decltype(invoke_impl::get(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>::call(std::forward<F>(f),
            std::forward<Args>(args)...));
} // namespace detail
 
// Minimal C++11 implementation:
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>()...));
};
 
// Conforming C++14 implementation (is also a valid C++11 implementation):
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...> {};

[編集] 注釈

C++11で定式化されたstd::result_ofの動作は、INVOKE(std::declval<F>(), std::declval<ArgTypes>()...)が不整形式の場合(例えば、Fが全く呼び出し可能な型でない場合)は未定義です。C++14では、これがSFINAEに変更されました(Fが呼び出し可能でない場合、std::result_of<F(ArgTypes...)>typeメンバを持たないだけです)。

std::result_ofの背後にある動機は、Callableの呼び出し結果を決定することです。特に、その結果型が異なる引数のセットに対して異なる場合です。

F(Args...)は、Args...を引数型とし、Fを戻り値型とする関数型です。そのため、std::result_ofにはいくつかの癖があり、C++17でstd::invoke_resultの代わりに非推奨になりました。

  • Fは関数型または配列型であってはならない(ただし、それらへの参照は可能)。
  • Argsのいずれかの型が「Tの配列」または関数型Tの場合、自動的にT*に調整されます。
  • FArgs...のいずれも抽象クラス型であってはならない。
  • Args...のいずれかがトップレベルのcv修飾子を持つ場合、それは破棄されます。
  • Args...のいずれもvoid型であってはならない。

これらの癖を避けるため、result_ofFArgs...に参照型と一緒に使用されることがよくあります。例えば

template<class F, class... Args>
std::result_of_t<F&&(Args&&...)> // instead of std::result_of_t<F(Args...)>, which is wrong
    my_invoke(F&& f, Args&&... args)
    {
        /* implementation */
    }

[編集] 注釈

機能テストマクロ 規格 機能
__cpp_lib_result_of_sfinae 201210L (C++14) std::result_ofSFINAE
__cpp_lib_is_invocable 201703L (C++17) std::is_invocable, std::invoke_result

[編集]

#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()
{
    // the result of invoking S with char and int& arguments is double
    std::result_of<S(char, int&)>::type d = 3.14; // d has type double
    static_assert(std::is_same<decltype(d), double>::value, "");
 
    // std::invoke_result uses different syntax (no parentheses)
    std::invoke_result<S,char,int&>::type b = 3.14;
    static_assert(std::is_same<decltype(b), double>::value, "");
 
    // the result of invoking S with int argument is float
    std::result_of<S(int)>::type x = 3.14; // x has type float
    static_assert(std::is_same<decltype(x), float>::value, "");
 
    // result_of can be used with a pointer to member function as follows
    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); // may fail to compile in C++11; calls the non-callable overload in C++14
}

出力

overload of f for non-callable T

[編集] 関連項目

(C++17)(C++23)
任意の呼び出し可能 (Callable)オブジェクトを所与の引数で呼び出す (戻り値の型を指定することも可能)(C++23以降)
(関数テンプレート) [編集]
ある型が与えられた引数型で(std::invokeのように)呼び出し可能であるかをチェックする
(クラステンプレート) [編集]
(C++11)
評価されない文脈で使用するために、テンプレート型引数のオブジェクトへの参照を取得する
(関数テンプレート) [編集]
English 日本語 中文(简体) 中文(繁體)