C++11 feature들에 대해서 대충 정리 함.
http://www.codeproject.com/Articles/570638/Ten-Cplusplus11-Features-Every-Cplusplus-Developer
[Lambda Expression]
- Lambda expression은 보통 a lambda function과 lambda를 지칭한다.
- anonymous function/function object를 정의 & 사용하기 위한 간략한 표기법
- algorithms이나 logic에서 operation을 argument로 전달할때 유용함. (callback과 같이)
Syntax
: http://en.cppreference.com/w/cpp/language/lambda
[ capture ] ( params ) mutable exception attribute -> ret { body } | (1) | ||||||||
[ capture ] ( params ) -> ret { body } | (2) | ||||||||
[ capture ] ( params ) { body } | (3) | ||||||||
[ capture ] { body } | (4) | ||||||||
1) Full declaration
2) Declaration of a const lambda: the objects captured by copy cannot be modified.
3) Omitted trailing-return-type: the return type of the closure's
operator()
is deduced according to the following rules:- if the body consists of the single return statement, the return type is the type of the returned expression (after rvalue-to-lvalue, array-to-pointer, or function-to-pointer implicit conversion)
- otherwise, the return type is void
4) Omitted parameter list: function takes no arguments, as if the parameter list was
()
Explanation
mutable | - | allows body to modify the parameters captured by copy, and to call their non-const member functions |
exception | - | provides the exception specification or the noexcept clause for operator() of the closure type |
attribute | - | provides the attribute specification for operator() of the closure type |
capture | - | specifies which symbols visible in the scope where the function is declared will be visible inside the function body.
A list of symbols can be passed as follows:
|
params | - | The list of parameters, as in named functions |
ret | - | Return type. If not present it's implied by the function return statements ( or void if it doesn't return any value) |
body | - | Function body |
[Example]
: http://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11
기존
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
Lambda 사용 시
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
사실 한곳이나 한번만 사용하는 일회성 function object인 경우 굳이 별도로 정의할 필요가 없어
사용되는 algorithms의 arguments로서 간략히 정의 하고자 하는 것이 장점.
trailing return type 형태로 return type 명시 예
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
}
else {
return d;
}
});
}
[Capture]
: lambda body내에서 사용할 argument 명시
- lambda는 inline 형태의 이름 없는 function/ function object로 어디서나 사용되어야 하므로 내부 변수를 참조 할 수 없다.
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
}
else {
return d;
}
});
}
You can capture by both reference and value, which you can specify using
=
and &
:[&epsilon]
capture by reference[&, epsilon]
specify that the default way of capturing is by reference and what we want to capture[=, &epsilon]
capture by value by default, but forepsilon
use reference instead
- [] 비어 있는 empty list
- [capture list] : explicit capture
- &, = 를 사용하여 capture by reference , capture by value 지정 가능
. [&] : implicitly capture by reference
. [=] : implicitly capture by value
. [&, capture list]
: implicitly capture by reference all local variables with names not mentioned in the list.
: capture list에 this는 포함 될 수 있음.
. [=, capture list] :
: implicitly capture by value all local variables with names not mentioned in the list.
: capture list에 this는 포함 될 수 없음.
ret operator()(params) const { body }
| (the keyword mutable was not used) | |
ret operator()(params) { body }
| (the keyword mutable was used) |
- 기본적으로 Lambda의 body는 operator()() prototype을 가지며 기본이 const이다.
: 만약 내부에서 captured variables를 수정하고 싶다면 mutable 속성을 지정해 주어야 한다.
void algo(vector<int>& v)
{
int count = v.size();
std::generate(v.begin(), v.end(),
[count]()mutable{ return --count; }
};
}
[Lambda and Lifetime]
lambda가 caller보다 lifetime이 길 경우 lambda에서 참조하는 arguments들의 확인이 필요함.
void setup(Menu& m)
{
Point p1, p2, p3;
m.add("draw triangle", [&]{m.draw(p1,p2,p3); }); // probable disater
}
위 예제에는 p1, p2, p3가 reference로 참조 되는 상태에서 lambda가 나중에 사용될 목적으로 저장 되는 상황이라 문제 발생 가능함. 이때는 reference & 에서 copy = 로 사용하는 것이 맞다.
- Lambda에서 name space를 capture할 필요는 없음.
- Lambda의 argument로 this를 사용할 수 있음. this는 call by reference로 참조되어 class instance의 member variable을 참조할 수 있음. 단 multi-threaded program에서 race condition 문제를 유발 가능.
[Call and Return]
- lambda가 argument를 받지 않는다면 생략 가능, 가장 minimal lambda expression = []{}
- lambda가 return type을 명시하지 않는다면 body를 통해 판단함. return이 있다면 return value의 type, 없다면 void
void g(double y)
{
[&]{ f(y); } // void
auto z1 = [=](int x){return x+y} // double
auto z2 = [=,y]{ if (y) return 1; else return 2;} // error : body is too complicated for return type deduction
auto z3 = [y]() { return 1: 2;} // int
auto z4 = [=,y]()->int { if (y) return 1; else return 2; } // explicit return type
}
- lambda는 template instantiation mechanism으로 인해 동일 type의 lambda가 동시에 사용될 수 없음.
* 일부 소스는 "The C++ Programming Language - Bjarne Stroustrup"에 포함된 예제 입니다.
void algo(vector<int>& v)
{
int count = v.size();
std::generate(v.begin(), v.end(),
[count]()mutable{ return --count; }
};
}
[Lambda and Lifetime]
lambda가 caller보다 lifetime이 길 경우 lambda에서 참조하는 arguments들의 확인이 필요함.
void setup(Menu& m)
{
Point p1, p2, p3;
m.add("draw triangle", [&]{m.draw(p1,p2,p3); }); // probable disater
}
위 예제에는 p1, p2, p3가 reference로 참조 되는 상태에서 lambda가 나중에 사용될 목적으로 저장 되는 상황이라 문제 발생 가능함. 이때는 reference & 에서 copy = 로 사용하는 것이 맞다.
- Lambda에서 name space를 capture할 필요는 없음.
- Lambda의 argument로 this를 사용할 수 있음. this는 call by reference로 참조되어 class instance의 member variable을 참조할 수 있음. 단 multi-threaded program에서 race condition 문제를 유발 가능.
[Call and Return]
- lambda가 argument를 받지 않는다면 생략 가능, 가장 minimal lambda expression = []{}
- lambda가 return type을 명시하지 않는다면 body를 통해 판단함. return이 있다면 return value의 type, 없다면 void
void g(double y)
{
[&]{ f(y); } // void
auto z1 = [=](int x){return x+y} // double
auto z2 = [=,y]{ if (y) return 1; else return 2;} // error : body is too complicated for return type deduction
auto z3 = [y]() { return 1: 2;} // int
auto z4 = [=,y]()->int { if (y) return 1; else return 2; } // explicit return type
}
- lambda는 template instantiation mechanism으로 인해 동일 type의 lambda가 동시에 사용될 수 없음.
* 일부 소스는 "The C++ Programming Language - Bjarne Stroustrup"에 포함된 예제 입니다.
댓글 없음:
댓글 쓰기