最終更新日時(UTC):
が更新

履歴 編集

class template
<type_traits>

std::invoke_result(C++17)

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が定義される場合、以下と同じ型となる:

decltype(std::invoke(std::declval<F&>(), std::declval<ArgsTypes&>()...)

備考

このメタ関数はresult_ofの代替として導入された。

result_ofは、シグニチャであることをわかりやすくするために、関数型でユーザーにテンプレート引数を指定させていたが、これは混乱の元であった。
例えばresult_of<F(Args...)>::typeと書くと、指定している関数呼び出し可能な型Fが戻り値型に見える、Fとして関数型や配列型(その参照ならok)を指定できない、F, Argsに抽象クラスを指定できない、Argsstd::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

処理系

参照