http://scor7910.tistory.com/55
Visual C++ 팀블로그에 C++0x에 대한 소개 자료중 람다(Lambda)에 관한 내용을 번역했습니다.
차후에 나머지도 번역해서 올리겠습니다.
번역이 만만치 않은 작업이근영....
원본 :
Lambdas, auto, and static_assert: C++0x Features in VC10, Part 1
마이크로소프트 비절 스투디오 2010CTP(Community Technology Preview)에서는 C++ 0x에 포함된 lambdas, auto, static_assert, rvalue references 라는 4가지의 개념을 제공합니다. 여기서는 처음 세가지에 대해 이야기를 하겠습니다.
첫번째로 , 내용을 쓰기전..:
1. 이 포스트는 Visual C++ 라이브러리 개발자인Stephan T. Lavavej 님이 작성했습니다. 그리고 Stephan T. Lavavej님이 위의 네가지 기능에 대한 구현을 담당하지 않았음을 밝힘니다.
2. 내용에서 VS 2010에서 Visual C++ 컴파일러를 VC10이라고 칭할 것 입니다(10은 2010의 약어가 아님).
3. C++0x는 아직 논의 중인 차세대 C++ 표준을 의미합니다.
(표준 위원회(The Standardization Committee) 2009에 C++09라는 이름으로 발표되기 원하지만 2010이나 더 걸릴수 있기 때문에 x를 붙였다는 조크도 있다네요. C++98 과 C++03 는 현재 C++ 표준을 의미 합니다.(여기서 역사이야기는 하지 않고 2003년에 발표된 C++표준은 1998년에 발표된 C++에 대한 단순한 “서비스팩” 이었고 대부분의 사람들은 이들의 차이점에 대해 무시하였죠. C++03 과 C++0x 는 완전히 다릅니다.
4. 나는 C++ 0x가 완벽하고 멋지게 구성하고 있을 표준 위원회(The Standardization Committee)에 감사를 표합니다. 그들은 또한 아래의 링크에 좋은 자료를 올려 두었습니다.
C++0x language feature status: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html
C++0x library feature status: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html
C++0x Working Draft: http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf
5. 어디에나 버그는 있습니다. (많지 않기를 원하지만..), 그게 CTP의 특성입니다. 버그가 발견되면 마이크로 소프트 커넥트에 리포팅 해주세요.
이제 본론으로 들어가겠습니다.
lambdas
C++0x에는 명명되지않은(unnamed) 함수객체(function objects)를 수동으로 선언과 정의를 하지않고, 이것을 포함하고 있는 함수객체(function objects)를 사용할 수 있는 “람다(lambda) 수식”이 있습니다.
아래는 람다를 사용한 "Hello, World" 예제 입니다. :
C:\Temp>type meow.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 meow.cpp > NUL && meow 0 1 2 3 4 5 6 7 8 9
|
[] 는 람다-소개자 (lambda-introducer) 입니다. 컴파일러에게 람다 수식이 시작했다는 것을 알려주는 역할을 합니다. (int n)은 람다-매개변수-선언(lambda-parameter-declaration) 입니다. 어떤 명명되지 않은(unnamed) 함수 객체 클래스의 연산자( ()연산자를 의미하는듯)가 실행이 되어지는지 컴파일러에게 알려주는 역할을 합니다. 마지막으로 { cout << n << " "; } 는 복합-서술(compound-statement)부분이고 , 명명되지 않은 함수 객체의 몸체(정의부) 입니다. 기본적으로 명명되지 않은 함수 객체의 연산자는 void를 리턴합니다.
그러면 C++0x에서 쓰여진 람다를 현재 C++로 구현한다면 어떻게 구현되는지 보겠습니다.
C:\Temp>type meow98.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
struct LambdaFunctor { void operator()(int n) const { cout << n << " "; } };
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
for_each(v.begin(), v.end(), LambdaFunctor()); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 meow98.cpp > NUL && meow98 0 1 2 3 4 5 6 7 8 9
|
이제부터 “명명되지않은 함수 객체 클래스의 () 연산자는 void를 리턴한다” 를 “람다는 void를 리턴한다”라고 말하겠습니다. 하지만, 람다 수식이 클래스를 정의하고 생성하는 것은 중요하니 기억해 두세요.
물론, 람다의 복합-서술(compound-statement)구문은 여러줄로 쓸 수 있습니다.
C:\Temp>type multimeow.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
for_each(v.begin(), v.end(), [](int n) { cout << n;
if (n % 2 == 0) { cout << " even "; } else { cout << " odd "; } });
cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 multimeow.cpp > NUL && multimeow 0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd
|
그리고, 람다는 항상 void를 리턴 하지 않습니다. 만약 람다의 복합-서술( compound-statement)이 { return expression; }로 되어 있다면, 람다의 리턴 타입은 자동으로 수식의 타입으로 만들어 줍니다.
C:\Temp>type cubicmeow.cpp #include <algorithm> #include <deque> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
deque<int> d;
transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });
for_each(d.begin(), d.end(), [](int n) { cout << n << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 cubicmeow.cpp > NUL && cubicmeow 729 512 343 216 125 64 27 8 1 0
|
여기서 n * n * n 는 int 타입이고 람다의 함수기 호출하는 ()연산자는 int를 리턴합니다.
람다로 더 복작한 복합-서술(compound-statements)구문은 자동으로 리턴타입을 만들어 줄 수 없습니다. 아래 코드와 같이 리턴타입을 명시해 주어야 합니다.
C:\Temp>type returnmeow.cpp #include <algorithm> #include <deque> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
deque<double> d;
transform(v.begin(), v.end(), front_inserter(d), [](int n) -> double { if (n % 2 == 0) { return n * n * n; } else { return n / 2.0; } });
for_each(d.begin(), d.end(), [](double x) { cout << x << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 returnmeow.cpp > NUL && returnmeow 4.5 512 3.5 216 2.5 64 1.5 8 0.5 0
|
“-> double” 은 부가적으로 사용할 수 있는 람다-리턴-타입-구문 (lambda-return-type-clause )입니다. 많은 개발자들이 왜 리턴 타입이 왼쪽에 오지 않는 건지 궁금해 하겠지만, lambda-introducer ( [] )가 앞에 있지 않으면 컴파일러는 람다 문법의 시작을 알수 없기 때문입니다.
만약 람다 리턴 타입 구문을 쓰지 않으면 다음과 같은 컴파일 에러가 발생됩니다.
C:\Temp>cl /EHsc /nologo /W4 borkedreturnmeow.cpp borkedreturnmeow.cpp borkedreturnmeow.cpp(20) : error C3499: a lambda that has been specified to have a void return type cannot return a value borkedreturnmeow.cpp(22) : error C3499: a lambda that has been specified to have a void return type cannot return a value |
지금까지 보여준 람다는 데이터 멤버가 없는(stateless) 것들입니다.
여러분들은 지역변수를 “캡쳐링(capturing)”해서 데이터 멤버를 가지고 있는 람다를 만들 수 있습니다. 비어있는 람다 소개자( lambda-introducer) [] 는 데이터 멤버가 없는 람다 라는 것을 의미 하고, 캡쳐리스트(capture-list)를 지정하여 데이터 멤버를 가지는 람다를 만들 수 있습니다.
C:\Temp>type capturekittybyvalue.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 0; int y = 0;
// op>>()는 입력 스트림에 개행 문자를 남겨야 하는데, // 이건 꽤 귀찮으므로 쓰지 않을 것을 추천합니다. // 대신 라인을 읽거나 읽어서 파싱하는 루틴을 만들고 // 싶다면getline(cin,str)함수를 사용하세요. // 여기서는 간단하게 쓰기 위해 op>>()를 썼습니다.
cout << "Input: "; cin >> x >> y;
v.erase(remove_if(v.begin(), v.end(), [x, y](int n) { return x < n && n < y; }), v.end());
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue.cpp > NUL && capturekittybyvalue Input: 4 7 0 1 2 3 4 7 8 9 |
캡쳐 리스트를 정의하지 않으면 아래의 오류 코드가 발생됩니다.
C:\Temp>cl /EHsc /nologo /W4 borkedcapturekittybyvalue.cpp borkedcapturekittybyvalue.cpp borkedcapturekittybyvalue.cpp(27) : error C3493: 'x' cannot be implicitly captured as no default capture mode has been specified borkedcapturekittybyvalue.cpp(27) : error C3493: 'y' cannot be implicitly captured as no default capture mode has been specified |
(기본(default) 캡쳐에 대한 설명은 나중에…)
람다 수식은 기본적으로 명명되지 않은 함수 객체 클래스를 정의 한다는 것을 기억해두시길 바랍니다. 복합-서술(compound-statement) 구문인 { return x < n && n < y; } 클래스의 ()연산자 함수 몸체에 해당됩니다.
어휘상 복합-서술(compound-statement) 구문이 어휘상 main() 함수 내부에 있지만 개념상 main()함수 외부에 존재 하는 것 입니다. 그래서 main() 함수 내부에 있는 지역변수를 바로 사용할 수 없고 람다 내부에서 캡쳐하여 사용해야 합니다.
아래 예제는 위의람다 캡쳐 예제를 현재 C++ 표준으로 구현한 것 입니다.
C:\Temp>type capturekittybyvalue98.cpp #include <algorithm> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
class LambdaFunctor { public: LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }
bool operator()(int n) const { return m_a < n && n < m_b; }
private: int m_a; int m_b; };
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 0; int y = 0;
cout << "Input: "; cin >> x >> y; // EVIL! <<- 이러면 안된다는 말입니다..
v.erase(remove_if(v.begin(), v.end(), LambdaFunctor(x, y)), v.end());
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue98.cpp > NUL && capturekittybyvalue98 Input: 4 7 0 1 2 3 4 7 8 9
|
여기서, 캡쳐의 의미가 “값에 의한(전달)” 이라는 것이 명확하게 알 수 있습니다. 지역변수의 복사본이 함수객체 내부 함수에 저장 되는 것을 볼 수 있습니다.
이는 함수 객체가 캡쳐하기 위해 생성된 지역변수 보다 더 오래 남을 수 있게 합니다.
아래 사항들을 알아 두세요.
(a) 함수호출 연산자( ()연산자 )는 기본적으로 const 이기 때문에, 캡쳐된 복사본은 람다 내부에서 수정될 수 없습니다.
(b) 어떤 객체는 복사하기 비용이 많이 듭니다.
(c) 지역변수를 변경하면 캡쳐된 복사본에는 아무런 영향을 없습니다. (값에의한 전달에 관한 내용).
이 부분은 다음에 필요할 때 이야기 하겠습니다.
캡쳐하고 싶은 지역변수들을 모두 지정하는 것 대신 “값에 의한 복사로 모두 캡쳐” 할 수 있습니다. 이것을 가능하게 하는 문법이 람다 소개자(lambda-introducer) 인 “ [=] “ 입니다. ( capture-default 인 ‘=’ 는 여러분이 대입연산자나 복사 초기화 Foo foo = bar 로 생각하게 하기 위함입니다;
사실 복사는 위의 예제에서 m_a(a) 같이 한번에 초기화 하기 위해 만들어 졌습니다.
C:\Temp>type defaultcapturekittybyvalue.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 0; int y = 0;
cout << "Input: "; cin >> x >> y; // EVIL!
v.erase(remove_if(v.begin(), v.end(), [=](int n) { return x < n && n < y; }), v.end());
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl; }
C:\Temp>cl /EHsc /nologo /W4 defaultcapturekittybyvalue.cpp > NUL && defaultcapturekittybyvalue Input: 4 7 0 1 2 3 4 7 8 9
|
컴파일러는 람다 구문 내에 있는 x와 y를 보고, main()함수에 있는 x와 y의 값을 캡쳐 합니다.
위에서 (a)항목에서 말한 람다의 함수 호출 연산자( () 연산자) 가 기본적으로 const이기 때문에 캡쳐한 복사본(원본)을 수정할 수 없지만, 람다 ()연산자 함수 내부에서 mutable(변하기 쉬운) 키워드를 사용하여 non-const로 만들면 됩니다.
C:\Temp>type capturekittybymutablevalue.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 1; int y = 1;
for_each(v.begin(), v.end(), [=](int& r) mutable { const int old = r;
r *= x * y;
x = y; y = old; });
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl;
cout << x << ", " << y << endl; }
C:\Temp>cl /EHsc /nologo /W4 capturekittybymutablevalue.cpp > NUL && capturekittybymutablevalue 0 0 0 6 24 60 120 210 336 504 1, 1 |
v에 있는 각 값에 이전의 x,y곱을 곱하는 동작을 합니다.
(이전의 모든 요소들과 곱해주도록 partial_sum() 함수나, 이전의 요소들과 바로 곱해주도록 adjacent_difference() 함수를 이용해서 구현할수 가 없어서 예제처럼 구현이 되어있습니다.) 위에서 말한 항목 “(d) 캡쳐된 복사본을 원본의 지역변수에 적용되지 않는다” 를 기억하세요.
위에 (b),(C),(d)의 약속을 우회할 방법을 알고 싶다면, 복사를 하지 않고 람다 내부에서 값을 변경하는 것을 관찰하는 방법, 람다함수 내부에서 값을 바꿀 수 있지 않을까요? 이럴 경우 참조(reference)로 값을 캡쳐하는 방법을 생각 했을 겁니다. 이렇게 하는 방법은 람다-소개자(lambda introducer)를 [&x, &y]로 하면 됩니다. ( [&x, &y] 를 X& x, Y& y로 생각하세요. 포인터의 전달이 아닌 참조(Reference)입니다.) :
C:\Temp>type capturekittybyreference.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 1; int y = 1;
for_each(v.begin(), v.end(), [&x, &y](int& r) { const int old = r;
r *= x * y;
x = y; y = old; });
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl;
cout << x << ", " << y << endl; }
C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference.cpp > NUL && capturekittybyreference 0 0 0 6 24 60 120 210 336 504 8, 9 |
위의 예제 capturekittybymutablevalue.cpp 와 다른 점은
(1)람다-소개자 모양( lambda-introducer) [&x, &y]
(2) mutable 키워드가 없습니다.
(3) main()함수 지역 변수 x,y의 값이 람다함수 내부에서 변경된 것이 main()함수에서도 적용되었습니다.
, 이 세가지 입니다.
위의 코드를 현재 C++로 구현 한다면 아래와 같이 구현할 수 있습니다.:
C:\Temp>type capturekittybyreference98.cpp #include <algorithm> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
#pragma warning(push) #pragma warning(disable: 4512) // assignment operator could not be generated
class LambdaFunctor { public: LambdaFunctor(int& a, int& b) : m_a(a), m_b(b) { }
void operator()(int& r) const { const int old = r;
r *= m_a * m_b;
m_a = m_b; m_b = old; }
private: int& m_a; int& m_b; };
#pragma warning(pop)
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int x = 1; int y = 1;
for_each(v.begin(), v.end(), LambdaFunctor(x, y));
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " ")); cout << endl;
cout << x << ", " << y << endl; }
C:\Temp>cl /EHsc /nologo /W4 capturekittybyreference98.cpp > NUL && capturekittybyreference98 0 0 0 6 24 60 120 210 336 504 8, 9
|
(람다를 사용하면 , 컴파일러는 자동으로 C4512 경고를 꺼줍니다.)
지역 변수를 참조로 캡쳐하면, 함수 객체는 참조(reference)를 자신의 참조(reference) 멤버변수에 저장합니다.
이렇게 하면 함수 객체 () 함수에서 변경된 값이 적용이 되는 겁니다.
(함수 객체의 ()함수 가 const인 것에 주의하세요. 우리는(VC++ 컴파일러팀) mutable이라 하지 않습니다. const를 붙인 것은 단순히 함수객체의 멤버 데이터의 변경을 막기 위함 입니다. 멤버데이터들은 참조하는 것 을 변경할수 없고 멤버 데이터들이 참조하는 값을 변경할 수 있습니다. Const가 아닌 함수 객체는 얕은 복사입니다.)
물론, 만약 람다함수 객체가 참조로 캡쳐된 지역변수들 보다 오래 생존(instantiate) 하게 되면 프로그램은 죽게 됩니다(crashtrocity : 뭔소리야?!!).
또한, 기본 캡쳐를 사용할 수도 있습니다. ; [&] 는 " 참조로 모든 변수를 캡쳐한다”를 의미 합니다.
만약 몇 개는 참조로하고 몇 개는 값으로 캡쳐하고 싶을땐 어떻게 할까요?
[a, b, c, &d, e, &f, g] 방법을 생각하겠지만, 여러분들은 capture-default 를 지정하고 특정 지역변수들에 대해 오버라이드 할 수 있습니다.
아래 예제는 위에 나온 예제capturekittybymutablevalue.cpp 를 수정한 것 입니다.:
C:\Temp>type overridekitty.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
int sum = 0; int product = 1;
int x = 1; int y = 1;
for_each(v.begin(), v.end(), [=, &sum, &product](int& r) mutable { sum += r;
if (r != 0) { product *= r; }
const int old = r;
r *= x * y;
x = y; y = old; });
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl;
cout << "sum: " << sum << ", product: " << product << endl; cout << "x: " << x << ", y: " << y << endl; }
C:\Temp>cl /EHsc /nologo /W4 overridekitty.cpp && overridekitty overridekitty.cpp 0 0 0 6 24 60 120 210 336 504 sum: 45, product: 362880 x: 1, y: 1 |
여기서는 x,y를 값으로 캡쳐하고, (람다 내부에서만 수정되어져야 하기 때문) sum, produce는 참조로 캡쳐 했습니다. 반대로 lambda-introducer를 [&, x, y] 로 해도 같은 같은 결과 입니다.
그럼 this 는 어떻게 할 까요?
C:\Temp>type memberkitty.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
class Kitty { public: explicit Kitty(int toys) : m_toys(toys) { }
void meow(const vector<int>& v) const { for_each(v.begin(), v.end(), [m_toys](int n) { cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl; }); }
private: int m_toys; };
int main() { vector<int> v;
for (int i = 0; i < 3; ++i) { v.push_back(i); }
Kitty k(5); k.meow(v); }
C:\Temp>cl /EHsc /nologo /W4 memberkitty.cpp memberkitty.cpp memberkitty.cpp(12) : error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope
|
람다 수식 문법은 지역변수를 캡쳐하는건 허용하지만 멤버 변수의 캡쳐는 허용하지 않습니다. 대신 특별히 this 포인터를 캡쳐 할 수 있습니다. :
C:\Temp>type workingmemberkitty.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
class Kitty { public: explicit Kitty(int toys) : m_toys(toys) { }
void meow(const vector<int>& v) const { for_each(v.begin(), v.end(), [this](int n) { cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl; }); }
private: int m_toys; };
int main() { vector<int> v;
for (int i = 0; i < 3; ++i) { v.push_back(i); }
Kitty k(5); k.meow(v); }
C:\Temp>cl /EHsc /nologo /W4 workingmemberkitty.cpp > NUL && workingmemberkitty If you gave me 0 toys, I would have 5 toys total. If you gave me 1 toys, I would have 6 toys total. If you gave me 2 toys, I would have 7 toys total. |
this를 캡쳐하면 m_toys멤버 변수는 암시적으로 this->m_toys를 의미 한다는 것을 생각 할 수 있습니다. (람다 수식 내부에선, this는 캡쳐된 this를 의미하지 람다 객체의 this포인터를 의미하지 않습니다. : 람다함수의 this 포인터에는 접근할 수 없습니다.)
this를 암시적으로 캡쳐할 수 있습니다:
C:\Temp>type implicitmemberkitty.cpp #include <algorithm> #include <iostream> #include <ostream> #include <vector> using namespace std;
class Kitty { public: explicit Kitty(int toys) : m_toys(toys) { }
void meow(const vector<int>& v) const { for_each(v.begin(), v.end(), [=](int n) { cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl; }); }
private: int m_toys; };
int main() { vector<int> v;
for (int i = 0; i < 3; ++i) { v.push_back(i); }
Kitty k(5); k.meow(v); }
C:\Temp>cl /EHsc /nologo /W4 implicitmemberkitty.cpp > NUL && implicitmemberkitty If you gave me 0 toys, I would have 5 toys total. If you gave me 1 toys, I would have 6 toys total. If you gave me 2 toys, I would have 7 toys total.
|
[&]로 할수 있지만 , this는 포함 되지 않습니다.(항상 값으로 전달됩니다.) , [&this]는 안됩니다.
람다 소개자(lambda-introducer)에 아무런 값을 넣고 싶지 않으면, lambda-parameter-declaration 전체는 생략 됩니다. :
C:\Temp>type nullarykitty.cpp #include <algorithm> #include <iostream> #include <iterator> #include <ostream> #include <vector> using namespace std;
int main() { vector<int> v;
int i = 0;
generate_n(back_inserter(v), 10, [&] { return i++; });
for_each(v.begin(), v.end(), [](int n) { cout << n << " "; }); cout << endl;
cout << "i: " << i << endl; }
C:\Temp>cl /EHsc /nologo /W4 nullarykitty.cpp > NUL && nullarykitty 0 1 2 3 4 5 6 7 8 9 i: 10
|
[&]() { return i++; }와 비교해서 2문자( () ) 가 빠져 있습니다 .
lambda-parameter-declaration 을 생략하는 건 여러분들 마음입니다.
장난 삼아 아래의 코드는 C++0x 에서 유효한 코드입니다.:
C:\Temp>type nokitty.cpp int main() { [](){}(); []{}(); }
|
위의 예제는 아무런 동작을 하지 않는 두 개의 람다를 생성합니다.
(첫 번째는 lambda-parameter-declaration이 있고 두 번째는 없습니다.)
추가적으로 사용할 수 있는 lambda-parameter-declaration 은 문법적으로 아래와 같이 구성되어있습니다. :
( lambda-parameter-declaration-listopt ) mutableopt exception-specificationopt lambda-return-type-clauseopt
그래서 mutable 이나 ->리턴타입 을 지정하고 싶으면 lambsa-introducer( [] )와 그 사이에 빈 공간이 필요 합니다.
마지막으로, 람다는 보통의 함수 객체를 만들어 내기 때문에 , 함수 객체들을 tr1::function 에 보관 할 수도 있습니다.:
C:\Temp>type tr1kitty.cpp #include <algorithm> #include <functional> #include <iostream> #include <ostream> #include <vector> using namespace std; using namespace std::tr1;
void meow(const vector<int>& v, const function<void (int)>& f) { for_each(v.begin(), v.end(), f); cout << endl; }
int main() { vector<int> v;
for (int i = 0; i < 10; ++i) { v.push_back(i); }
meow(v, [](int n) { cout << n << " "; }); meow(v, [](int n) { cout << n * n << " "; });
function<void (int)> g = [](int n) { cout << n * n * n << " "; };
meow(v, g); }
C:\Temp>cl /EHsc /nologo /W4 tr1kitty.cpp > NUL && tr1kitty 0 1 2 3 4 5 6 7 8 9 0 1 4 9 16 25 36 49 64 81 0 1 8 27 64 125 216 343 512 729
|
'Programming' 카테고리의 다른 글
(C) Unix Daemon Server Programming (0) | 2013.04.24 |
---|---|
(C) tcpredir.c: TCP redirection (port forwarding) (0) | 2013.04.24 |
(Visual C++ 2010) Examples of Lambda Expressions (0) | 2013.04.14 |
(JavaScript) How to make a cool $() selector (0) | 2013.04.09 |
(JavaScript) Canvas tutorial - HTML | MDN (0) | 2013.04.03 |