반응형


출처 : http://scor7910.tistory.com/55



Visual C++ 팀블로그에 C++0x에 대한 소개 자료중 람다(Lambda)에 관한 내용을 번역했습니다. 
차후에 나머지도 번역해서 올리겠습니다. 
번역이 만만치 않은 작업이근영....

 원본 : 

http://blogs.msdn.com/vcblog/archive/2008/10/28/lambdas-auto-and-static-assert-c-0x-features-in-vc10-part-1.aspx

 

Lambdas, auto, and static_assert: C++0x Features in VC10, Part 1

마이크로소프트 비절 스투디오 2010CTP(Community Technology Preview)에서는 C++ 0x 포함된 lambdasautostatic_assertrvalue 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), [](intn) -> 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) { returnx < 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

 

 

반응형

+ Recent posts