namespace std {
template <class F, class... ArgsTypes>
struct invoke_result;
template <class F, class... ArgsTypes>
using invoke_result_t = typename invoke_result<F, ArgsTypes...>::type;
}
概要
与えられた型の引数(ArgsTypes...)で関数呼び出し可能な型(F)について、関数呼び出しの戻り値型を取得する。
要件
型F
およびArgsTypes...
パラメータパックの全ての型が、完全型であること。もしくはconst
/volatile
修飾された(あるいはされていない)void
か、要素数不明の配列型であること。
効果
INVOKE要件に従った呼び出しの結果(戻り値)となる型をメンバ型type
として定義する。そのような呼び出しが出来ない(ill-formedな)場合、メンバ型type
は定義されない。
すなわち、関数呼び出し出来ない型と引数列の組み合わせが渡された場合、SFINAEが働く。
メンバ型type
が定義される場合、以下と同じ型となる:
備考
このメタ関数はresult_of
の代替として導入された。
result_of
は、シグニチャであることをわかりやすくするために、関数型でユーザーにテンプレート引数を指定させていたが、これは混乱の元であった。
例えばresult_of<F(Args...)>::type
と書くと、指定している関数呼び出し可能な型F
が戻り値型に見える、F
として関数型や配列型(その参照ならok)を指定できない、F, Args
に抽象クラスを指定できない、Args
はstd::decay
を通したように変換される等の問題があり、規格書内でresult_of
を参照している個所に混乱やバグを導入してしまっていた。
そのため、result_of
のテンプレート引数型の変更が考えられていたが、std::invoke()
導入に当たって関連するメタ関数の命名規則が統一されたため、result_of
は非推奨とされinvoke_result
として本メタ関数が導入された。
例
#include <type_traits>
#include <vector>
#include <string>
struct functor {
auto operator()() -> int {
return 0;
}
auto operator()(int, double) -> std::string {
return "string";
}
};
struct has_member {
short member_function(std::vector<char>) {
return 0;
}
int member_object;
};
auto f(int) -> double {
return 0.0;
}
template<typename Expected, typename F, typename... Args>
using check_r = std::is_same<Expected, typename std::invoke_result<F, Args...>::type>;
int main()
{
//has_member.*(has_member::*member_function, std::vector<char>) -> short
static_assert(check_r<short, decltype(&has_member::member_function), has_member, std::vector<char>>::value);
//(*(has_member*)).*(has_member::*member_function, std::vector<char>) -> short
static_assert(check_r<short, decltype(&has_member::member_function), has_member*, std::vector<char>>::value);
//has_member.*(has_member::*member_object) -> int&&
static_assert(check_r<int&&, decltype(&has_member::member_object), has_member>::value);
//(*(has_member*)).*(has_member::*member_object) -> int&
static_assert(check_r<int&, decltype(&has_member::member_object), has_member*>::value);
//functor::operator()() -> int
static_assert(check_r<int, functor>::value);
//functor::operator()(int, double) -> std::string
static_assert(check_r<std::string, functor, int, double>::value);
//f(int) -> double;
static_assert(check_r<double, decltype(f), int>::value);
}
出力
バージョン
言語
- C++17
処理系
- Clang: 6.0 ✅
- GCC: 7.3 ✅
- Visual C++: 2017 Update 3 ✅