namespace std {
template <class> class result_of; // 宣言のみ
template <class F, class... ArgTypes>
class result_of<F(ArgTypes...)> {
using type = …;
};
template <class T>
using result_of_t = typename result_of<T>::type;
}
この機能はC++17から非推奨となり、C++20で削除された。代わりにstd::invoke_result
を使用すること。
概要
関数の戻り値の型を取得する。
要件
- C++11まで : 型
F
は、関数または関数オブジェクトであること。もしくは、型F
は、関数または関数オブジェクトへの参照であること。INVOKE(declval<Fn>(), declval<ArgTypes>()...)
が有効な式であること。 - C++14から : 型
F
およびArgsTypes...
パラメータパックの全ての型が、完全型であること。もしくはconst
/volatile
修飾された(あるいはされていない)void
か、要素数不明の配列型であること。- このバージョンでは要件が緩和され、関数呼び出しが可能であることが要件から外れた。これにより、有効でない関数オブジェクト、引数を指定した場合に、
static_assert
でコンパイルエラーにならず、テンプレートの置き換え失敗によりSFINAEが働くようになった。
- このバージョンでは要件が緩和され、関数呼び出しが可能であることが要件から外れた。これにより、有効でない関数オブジェクト、引数を指定した場合に、
効果
result_of
は、関数または関数オブジェクトの型F
に対して、ArgTypes...
を引数として渡した場合の戻り値の型を、メンバ型type
として定義する。
メンバ型type
は、以下と同じ型になる:
C++14以降では、上記メンバ型type
の型定義が有効な式でない場合、メンバ型type
は定義されない。
非推奨・削除の詳細
C++17で特定のシグニチャで関数呼び出しが可能かを判定するis_callable
を導入する予定だったが、std::invoke()
関数を導入する際に、result_of
も含めて命名規則を統一することとなった。
is_callable
はstd::is_invocable
という名前で導入された。
result_of
は、シグニチャであることをわかりやすくするために、関数型でユーザーにテンプレート引数を指定させていたが、これは混乱の元であった。
そのため、std::invoke_result
に名称変更することとなった。
例
#include <iostream>
#include <string>
#include <type_traits>
#include <functional>
// 関数
int func(int a, int b)
{ return a + b; }
// 関数オブジェクト
struct functor {
int operator()(int a, int b) const
{
return a + b;
}
// オーバーロードしている
std::string operator()(std::string a, std::string b) const
{
return a + b;
}
};
struct X {
// メンバ関数
int foo(int a, int b) const
{
return a + b;
}
};
// 受け取った関数を呼び出し、その関数の戻り値を返す
template <class F, class... Args>
typename std::result_of<F(Args...)>::type
invoke(F&& f, Args... args)
{
return f(args...);
}
// Fがメンバ関数ポインタの場合
template <class F, class... Args>
typename std::result_of<F(Args...)>::type
invoke_memfun(F&& f, Args... args)
{
return std::bind(std::move(f), args...)();
}
int main()
{
// 関数
int result1 = invoke(func, 1, 2);
// 関数オブジェクト
int result2 = invoke(functor(), 1, 2);
// オーバーロード
std::string result3 = invoke(functor(), "Hello ", "World");
// メンバ関数
X x;
int result4 = invoke_memfun(&X::foo, x, 1, 2);
std::cout << result1 << std::endl;
std::cout << result2 << std::endl;
std::cout << result3 << std::endl;
std::cout << result4 << std::endl;
}
出力
3
3
Hello World
3
バージョン
言語
- C++11
処理系
- Clang: 3.0 ✅
- GCC: 4.6.4 ✅
- Visual C++: 2008 (std::tr1) ✅, 2010 ✅, 2012 ✅, 2013 ✅, 2015 ✅
- 2008~2010は、TR1に基づく実装である。
decltype
を使用せず、関数オブジェクトに定義されたresult_type
が使用される。 - 2012までは、可変引数テンプレートに対応していないため、不完全な実装である。
result_of_t
は、2013から。
- 2008~2010は、TR1に基づく実装である。
参照
- N1437 A uniform method for computing function object return types
- N1454 A uniform method for computing function object return types (revision 1)
- Bringing result_of near to INVOKE
- N3462
std::result_of
and SFINAE- C++11では、テンプレートパラメータが有効な関数の式にならない場合に
static_assert
でコンパイルエラーにしていたが、C++14ではその時点でコンパイルエラーにせず、SFINAEを働かせるようにした。
- C++11では、テンプレートパラメータが有効な関数の式にならない場合に
- N3546 TransformationTraits Redux
- N3655 TransformationTraits Redux, v2
- P0604R0 Resolving GB 55, US 84, US 85, US 86
- P0619R4 Reviewing deprecated facilities of C++17 for C++20