パート LII. std::invoke ( C++17 )

目次

334. std::optional との合わせ技

std::invoke は呼び出し可能なオブジェクトを実行する関数です。

クラスメンバー関数の呼び出しを少しだけ使いやすくしてくれる関数というのが筆者の理解です。

//<functional>
template< class F, class... Args>
std::invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) noexcept

f が Callable なオブジェクトであれば args を引数として実行します。

コーラブルオブジェクトの抽象化をしてるわけですが、設計上 f を固定したくないなら使えそうですね。

戻り値型の std::invoke_result_t は呼び出し結果の型となり std::invoke_result というクラステンプレートの型にしたものです。

では簡単な実装例を見てみましょう。

注記

マクロについては クロスコンパイルのための組み込みマクロ を参照くださいね。

main.cpp. 

  1 #if __cplusplus < 201703L
  2 # pragma message "-std=c++17を指定してください"
  3 #endif
  4
  5 #include <functional> //invoke
  6 #include <tuple>
  7 #include <iostream>
  8
  9 int foo(int x, int y) {
 10   return x + y;
 11 }
 12
 13 int main()
 14 {
 15   auto invoke_result = std::invoke(foo,10,2);
 16   std::cout << invoke_result << '\n';
 17
 18   return 0;
 19 }

ビルドと実行. 

$ g++ main.cpp -std=c++17
$ ./a.out
12

std::invoke が関数 foo を呼び出してるのがわかるかと思います。

 15   auto invoke_result = std::invoke(foo,10,2);

この行では 10 と 2 は foo の引数となります。

まあこの辺は特に難しないですね。

ではメンバー関数の呼び出しに使うとどうでしょうかね?

main.cpp. 

  1 #if __cplusplus < 201703L
  2 # pragma message "-std=c++17を指定してください"
  3 #endif
  4
  5
  6 #include <functional> //invoke
  7 #include <tuple>
  8 #include <iostream>
  9
 10 struct Foo {
 11   int print(int x, int y)
 12   {
 13     return x + y;
 14   }
 15 };
 16
 17 int main()
 18 {
 19   Foo foo;
 20   auto invoke_result = std::invoke(&Foo::print,foo,10,2);
 21   std::cout << invoke_result << '\n';
 22
 23   return 0;
 24 }

ビルドと実行. 

$ g++ main.cpp -std=c++17
$ ./a.out
12

この例を見てもらうと第一引数にメンバー関数、第二引数にオブジェクトを指定するだけです。

Copyright 2017-2018, by Masaki Komatsu