ラムダ式の例
このトピックには、プログラムでのラムダ式の使用方法を示す例が含まれています。ラムダ式の概要については、「C++ でのラムダ式」を参照してください。ラムダ式の構造の詳細については、「ラムダ式の構文」を参照してください。
このセクションの内容
例: ラムダ式の宣言
例: ラムダ式の呼び出し
例: ラムダ式の入れ子
例: 高階ラムダ関数
例: メソッドでのラムダ式の使用
例: テンプレートでのラムダ式の使用
例: 例外処理
例: マネージ型でのラムダ式の使用
例: ラムダ式の宣言
説明
ラムダ式が入力されたため、次の例に示すように auto 変数または function オブジェクトに割り当てることもできます。
コード
// declaring_lambda_expressions1.cpp
#include <functional>
int main()
{
// Assign the lambda expression that adds two numbers to an auto variable.
auto f1 = [] (int x, int y) { return x + y; };
// Assign the same lambda expression to a function object.
function<int (int, int)> f2 = [] (int x, int y) { return x + y; };
}
コメント
auto キーワードの詳細については、「auto キーワード (の型推論)」を参照してください。function class の詳細については、「function クラス」を参照してください。
ラムダ式はメソッドまたは関数の本体で最も頻繁に宣言されますが、変数を初期化できる場所ならどこでも宣言できます。
説明
Visual C++ コンパイラは、式が呼び出されるときではなく式が宣言されるときにラムダ式をキャプチャされた変数にバインドします。次の例では、ローカル変数 i を明示的に値でキャプチャし、ローカル変数 j を暗黙的に参照でキャプチャするラムダ式を示しています。ラムダ式では値により i をキャプチャするため、プログラムで後で i を再割り当てしても式の結果に影響しません。ただし、ラムダ式では参照により j をキャプチャするため、j の再割り当ては式の結果に影響します。
コード
// declaring_lambda_expressions2.cpp
// compile with: /EHsc
#include <iostream>
#include <functional>
int main()
{
using namespace std;
int i = 3;
int j = 5;
// The following lambda expression captures i by value and
// j by reference.
function<int (void)> f = [i, &j] { return i + j; };
// Change the values of i and j.
i = 22;
j = 44;
// Call f and print its result.
cout << f() << endl;
}
出力
47
コメント
[このセクションの内容]
例: ラムダ式の呼び出し
ラムダ式は、直接呼び出すか、find_if などの標準テンプレート ライブラリ (STL) アルゴリズムに引数として渡すことができます。
説明
次の例は、2 つの整数値の合計を返し、引数 5 と 4 と共に直ちに式を呼び出すラムダ式を宣言します。
コード
// calling_lambda_expressions1.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
using namespace std;
int n = [] (int x, int y) { return x + y; }(5, 4);
cout << n << endl;
}
出力
9
説明
次の例は、find_if 関数の引数としてラムダ式を渡します。ラムダ式は、パラメーターが偶数の場合、true を返します。
コード
// calling_lambda_expressions2.cpp
// compile with: /EHsc
#include <list>
#include <algorithm>
#include <iostream>
int main()
{
using namespace std;
// Create a list of integers with a few initial elements.
list<int> numbers;
numbers.push_back(13);
numbers.push_back(17);
numbers.push_back(42);
numbers.push_back(46);
numbers.push_back(99);
// Use the find_if function and a lambda expression to find the
// first even number in the list.
const list<int>::const_iterator result =
find_if(numbers.begin(), numbers.end(),
[](int n) { return (n % 2) == 0; });
// Print the result.
if (result != numbers.end())
{
cout << "The first even number in the list is "
<< (*result)
<< "."
<< endl;
}
else
{
cout << "The list contains no even numbers."
<< endl;
}
}
出力
The first even number in the list is 42.
コメント
find_if 関数の詳細については、「find_if」を参照してください。アルゴリズムを実行する STL 関数の詳細については、「<algorithm>」を参照してください。
説明
関数呼び出し演算子、operator() を使用して、変数に割り当てられたラムダ式を呼び出すことができます。次の例では、ラムダ式を auto 変数に割り当て、次に関数呼び出し演算子を使ってラムダ式を呼び出します。
コード
// calling_lambda_expressions3.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
using namespace std;
// Assign the lambda expression that adds two numbers to an
// auto variable.
auto f = [] (int x, int y) { return x + y; };
// Invoke the function object and print its result.
cout << f(21, 12) << endl;
}
出力
33
コメント
関数呼び出し演算子の詳細については、「関数呼び出し (C++)」を参照してください。
[このセクションの内容]
例: ラムダ式の入れ子
説明
ラムダ式を、別の式の入れ子にすることができます。次の例では、他のラムダ式を含むラムダ式を示しています。内側のラムダ式は、その引数を 2 倍し、その結果を返します。外部のラムダ式は、引数を持つ内部のラムダ式を呼び出し、結果に 3 を追加します。
コード
// nesting_lambda_expressions.cpp
// compile with: /EHsc
#include <iostream>
int main()
{
using namespace std;
// The following lambda expression contains a nested lambda
// expression.
int m = [](int x)
{ return [](int y) { return y * 2; }(x) + 3; }(5);
// Print the result.
cout << m << endl;
}
出力
13
コメント
この例では、[](int y) { return y * 2; } は入れ子になったラムダ式です。
[このセクションの内容]
例: 高階ラムダ関数
説明
多くのプログラミング言語は高階関数の概念をサポートしています。高階関数は、引数として別のラムダ式を使用するか、ラムダ式を返すラムダ式です。function クラスを使用すると、C.C++ ラムダ式が高階関数のように動作できるようになります。次の例は、function のオブジェクトを返すラムダ式と、function オブジェクトを引数として受け取るラムダ式を示しています。
コード
// higher_order_lambda_expression.cpp
// compile with: /EHsc
#include <iostream>
#include <functional>
int main()
{
using namespace std;
// The following code declares a lambda expression that returns
// another lambda expression that adds two numbers.
// The returned lambda expression captures parameter x by value.
auto g = [](int x) -> function<int (int)>
{ return [=](int y) { return x + y; }; };
// The following code declares a lambda expression that takes another
// lambda expression as its argument.
// The lambda expression applies the argument z to the function f
// and adds 1.
auto h = [](const function<int (int)>& f, int z)
{ return f(z) + 1; };
// Call the lambda expression that is bound to h.
auto a = h(g(7), 8);
// Print the result.
cout << a << endl;
}
出力
16
コメント
[このセクションの内容]
例: メソッドでのラムダ式の使用
説明
メソッドの本体でラムダ式を使用できます。ラムダ式は、外側のメソッドがアクセスできる任意のメソッドまたはデータ メンバーにアクセスできます。this ポインターを明示的にまたは暗黙でキャプチャして、外側のクラスのメソッドとデータ メンバーへのアクセスを提供できます。
次の例は、スケール値をカプセル化する Scale クラスを示しています。ApplyScale メソッドは、ラムダ式を使用して vector オブジェクト内の各要素の結果およびスケール値を印刷します。ラムダ式は、_scale メンバーにアクセスできるように this ポインターを明示的に取得します。
// method_lambda_expression.cpp
// compile with: /EHsc
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Scale
{
public:
// The constructor.
explicit Scale(int scale)
: _scale(scale)
{
}
// Prints the product of each element in a vector object
// and the scale value to the console.
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[this](int n) { cout << n * _scale << endl; });
}
private:
int _scale;
};
int main()
{
vector<int> values;
values.push_back(3);
values.push_back(6);
values.push_back(9);
// Create a Scale object that scales elements by 3 and apply
// it to the vector object.
Scale s(3);
s.ApplyScale(values);
}
出力
9
18
27
コメント
次の例に示すように、this ポインターを明示的に使用できます。
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[this](int n) { cout << n * this->_scale << endl; });
}
また、次の例に示すように、this ポインターを暗黙的にキャプチャすることもできます。
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(),
[=](int n) { cout << n * _scale << endl; });
}
[このセクションの内容]
例: テンプレートでのラムダ式の使用
説明
ラムダ式が入力されるため、それらを C++ テンプレートで使用できます。negate_all 関数および print_all 関数の例を次に示します。negate_all 関数は、単項 operator- を vector オブジェクトの各要素に適用します。print_all 関数は、vector オブジェクトの各要素をコンソールに出力します。
コード
// template_lambda_expression.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
// Negates each element in the vector object.
template <typename T>
void negate_all(vector<T>& v)
{
for_each(v.begin(), v.end(), [] (T& n) { n = -n; } );
}
// Prints to the console each element in the vector object.
template <typename T>
void print_all(const vector<T>& v)
{
for_each(v.begin(), v.end(), [] (const T& n) { cout << n << endl; } );
}
int main()
{
// Create a vector of integers with a few initial elements.
vector<int> v;
v.push_back(34);
v.push_back(-43);
v.push_back(56);
// Negate each element in the vector.
negate_all(v);
// Print each element in the vector.
print_all(v);
}
出力
-34
43
-56
コメント
C++ テンプレートの詳細については、「テンプレート」を参照してください。
[このセクションの内容]
例: 例外処理
説明
ラムダ式の本体は、構造化例外処理 (SEH: Structured Exception Kandling) および C++ 例外処理の規則に従います。発生した例外をラムダ式の本体で処理するか、または例外処理を外側のスコープに延期することができます。次の例は、for_each 関数と、一方の vector オブジェクトに他方の値を挿入するラムダ式を使用します。これは、try/catch ブロックを使用して、最初のベクターへの無効なアクセスを処理します。
コード
// eh_lambda_expression.cpp
// compile with: /EHsc
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
// Create a vector that contains 3 elements.
vector<int> elements(3);
// Create another vector that contains index values.
vector<int> indices(3);
indices[0] = 0;
indices[1] = -1; // This is not a subscript. It will trigger the exception.
indices[2] = 2;
// Use the values from the vector of index values to
// fill the elements vector. This example uses a
// try/catch block to handle invalid access to the
// elements vector.
try
{
for_each(indices.begin(), indices.end(),
[&] (int index) { elements.at(index) = index; });
}
catch (const out_of_range& e)
{
cerr << "Caught '" << e.what() << "'." << endl;
};
}
出力
Caught 'invalid vector<T> subscript'.
コメント
例外処理の詳細については、「Visual C++ の例外処理」を参照してください。
[このセクションの内容]
例: マネージ型でのラムダ式の使用
説明
ラムダ式の capture 句には、マネージ型の変数を含めることができません。ただし、ラムダ式のパラメーター リストにマネージ型の引数を渡すことができます。次の例は、ローカル非マネージ型変数 ch を値でキャプチャするラムダ式を含み、そのパラメーターとして System.String オブジェクトを受け取ります。
コード
// managed_lambda_expression.cpp
// compile with: /clr
using namespace System;
int main()
{
char ch = '!'; // a local unmanaged variable
// The following lambda expression captures local variables
// by value and takes a managed String object as its parameter.
[=] (String ^s)
{ Console::WriteLine(s + Convert::ToChar(ch)); }("Hello");
}
出力
Hello!
コメント
ラムダ式を STL/CLR ライブラリで使用することもできます。STL/CLR の詳細については、「STL/CLR ライブラリの参照」を参照してください。
[このセクションの内容]