名前空間
変種
操作

std::result_of, std::invoke_result

提供: cppreference.com
< cpp‎ | types
 
 
 
型サポート
型プロトタイプ
(C++11)
(C++11)
(C++14)
(C++11)
(C++11)(C++20以前)
(C++11)(C++20で非推奨)
(C++11)
型特性定数
メタ関数
(C++17)
エンディアン
(C++20)
サポートされている操作
関係と性質の問い合わせ
(C++11)
(C++11)
型変更
(C++11)(C++11)(C++11)
型変換
(C++11)
(C++11)
(C++17)
result_ofinvoke_result
(C++11)(C++20以前)(C++17)
 
ヘッダ <type_traits> で定義
template< class >

class result_of; // not defined

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 は呼び出し可能な型、関数への参照、または呼び出し可能な型への参照でなければなりません。 ArgTypes... を用いた F の呼び出しは well-formed な式でなければなりません。

(C++11およびそれ以降)
(C++14以前)

F および ArgTypes のすべての型は任意の完全型、サイズの不明な配列、 void または cv 修飾された void にできます。

(C++14およびそれ以降)

目次

[編集] メンバ型

メンバ型 定義
type 引数 ArgTypes... で呼び出した場合の Callable な型 F の戻り値の型。 未評価文脈において 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 の策定時、 INVOKE(std::declval<F>(), std::declval<ArgTypes>()...) が ill-formed であれば (例えば F がまったく呼び出し可能な型でないなど)、 std::result_of の動作は未定義でした。 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_of ではしばしば F および Args... として参照型が使用されます。 例えば、

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 */
}

[編集]

#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\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, "");
 
    // 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)
任意の Callable なオブジェクトを指定された引数で呼びます
(関数テンプレート) [edit]
型が指定された引数型で (std::invoke によるかのように) 呼ぶことが可能かどうか調べます
(クラステンプレート) [edit]
(C++11)
未評価文脈で使用するための引数への参照を取得します
(関数テンプレート) [edit]