開発を行っているとラムダ式を格納したり、クラスのオブジェクトごとに処理を入れ込みたい時があります。
今回はC++の標準機能を使用して、ラムダ式を格納する方法を紹介します。
前提知識
- ラムダ式の理解
- クラステンプレートの理解
関数を格納といえば…
関数を格納するといえば関数ポインタでしたよね。
関数ポインタは戻り値の型 (*関数ポインタ名)(引数リスト)
で宣言が可能でした。
まずは当てはめて試してみましょう。
#include <iostream>
int main() {
int x = 10;
int y = 5;
int (*compute)(int, int) = nullptr; //整数同士の演算結果を返す関数ポインタの宣言
compute = [](int x, int y) {return x + y; }; //加算処理を代入
printf_s("演算結果:%d\n", compute(x, y)); //演算結果を出力(15)
compute = [](int x, int y) {return x - y; }; //減算処理を代入
printf_s("演算結果:%d\n", compute(x, y)); //演算結果を出力(5)
system("pause");
return 0;
}
演算結果:15
演算結果:5
続行するには何かキーを押してください . . .
関数ポインタでラムダ式の格納に成功しました。
次はキャプチャを使って記述してみたい。
キャプチャを使ったラムダ式の格納
今回はキャプチャで既存の値をコピーしたラムダ式を格納します。
キャプチャがわからない方は、下記のサイトにてご参照ください。
#include <iostream>
#include <functional>
int main() {
int x = 10;
int y = 5;
int (*compute)() = nullptr; //整数同士の演算結果を返す関数ポインタ
compute = [=]() {return x + y; }; //加算処理を代入
printf_s("演算結果:%d\n", compute()); //演算結果を出力(15)
compute = [=]() {return x - y; }; //減算処理を代入
printf_s("演算結果:%d\n", compute()); //演算結果を出力(5)
system("pause");
return 0;
}
E0413 "lambda []()->int" から "int (*)(int, int)" への適切な変換関数が存在しません
E0140 関数呼び出しの引数が多すぎます
E0413 "lambda [](int x, int y)->int" から "int (*)(int, int)" への適切な変換関数が存在しません
E0140 関数呼び出しの引数が多すぎます
C2440 '=': 'main::<lambda_1>' から 'int (__cdecl *)(int,int)' に変換できません。
C2197 'int (__cdecl *)(void)': 呼び出しに対する引数が多すぎます
C2440 '=': 'main::<lambda_2>' から 'int (__cdecl *)(int,int)' に変換できません。
C2197 'int (__cdecl *)(void)': 呼び出しに対する引数が多すぎます
コンパイルエラーが出ました。
関数ポインタでは単純に関数を格納だけなので、キャプチャを行う場合は関数ポインタでは機能が不十分なのです。
どうすればよいのか
結論から言うとstd::function
型を使うことでキャプチャしたラムダ式を格納することができます。
std::function
は<functional>
をinclude
することで使用できます。
#include <iostream>
#include <functional>
int main() {
int x = 10;
int y = 5;
std::function<int()> compute = nullptr; //整数同士の演算結果を返す関数ポインタ
compute = [=]() {return x + y; }; //加算処理を代入
printf_s("演算結果:%d\n", compute()); //演算結果を出力(15)
compute = [=]() {return x - y; }; //減算処理を代入
printf_s("演算結果:%d\n", compute()); //演算結果を出力(5)
system("pause");
return 0;
}
演算結果:15
演算結果:5
続行するには何かキーを押してください . . .
成功しました。
文法としてはstd::function<戻り値の型(引数リスト)>
で宣言が可能です。
また、この方法でクラス内にキャプチャしたラムダ式を格納することも可能です。
#include <iostream>
#include <functional>
//演算を行う関数オブジェクトを格納するだけのクラス
class ComputeFunctionHolder {
public:
ComputeFunctionHolder(std::function<int()> input_func); //コンストラクタ
void ShowResult(); //格納している関数を呼び、結果を出力
private:
std::function<int()> compute_function_; //関数オブジェクトを格納する変数
};
//コンストラクタ
//第一引数:格納したい関数オブジェクト
ComputeFunctionHolder::ComputeFunctionHolder(std::function<int()> input_func) {
compute_function_ = input_func;
}
//格納している関数を呼び、結果を出力
void ComputeFunctionHolder::ShowResult() {
printf_s("演算結果:%d\n", compute_function_());
}
int main() {
int x = 10;
int y = 5;
ComputeFunctionHolder add([=]() {return x + y; }); //加算処理を格納するインスタンス
add.ShowResult(); //演算結果を出力(15)
ComputeFunctionHolder sub([=]() {return x - y; }); //減算処理を格納するインスタンス
sub.ShowResult(); //演算結果を出力(5)
system("pause");
return 0;
}
演算結果:15
演算結果:5
続行するには何かキーを押してください . . .
成功です。
この方法で、クラス外の変数を見た関数を格納することが可能となります。
総括
- キャプチャを行わないラムダ式は関数ポインタに代入できる。
- キャプチャを行う場合は関数ポインタでは機能が不十分であり、
std::function
を使用することで格納が可能となる。 -
std::function
を応用することで、クラス外の変数を使用した処理を格納することも可能となる。