기본 콘텐츠로 건너뛰기

C++ 0x : 람다(Lambda)



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

마이크로소프트 비절 스투디오 2010CTP(Community Technology Preview)에서는 C++ 0x 포함된 lambdasautostatic_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) 감사를 표합니다그들은 또한 아래의 링크에 좋은 자료를 올려 두었습니다 

5.  어디에나 버그는 있습니다. (많지 않기를 원하지만..), 그게  CTP 특성입니다버그가 발견되면 마이크로 소프트 커넥트 리포팅 해주세요.

이제 본론으로 들어가겠습니다.





lambdas
C++0x에는 명명되지않은(unnamed) 함수객체(function objects) 수동으로 선언과 정의를 하지않고이것을 포함하고 있는  함수객체(function objects) 사용할  있는 람다(lambda) 수식 있습니다.
아래는 람다를 사용한 "Hello, World" 예제 입니다. :

C:\Temp>type meow.cpp
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
using namespace std;

struct LambdaFunctor {
    void operator()(int n) const {
        cout << n << " ";
    }
};

int main() {
    vector 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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main() {
    vector<int> v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    deque 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 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main() {
    vector v;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
    }

    deque 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 
#include 
#include 
#include 
using namespace std;

int main() {
    vector 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 
#include 
#include 
#include 
#include 
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 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(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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
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(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 
#include 
#include 
#include 
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 
#include 
#include 
#include 
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& 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 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 
#include 
#include 
#include 
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& 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
#include
#include
#include
using namespace std;

class Kitty {
public:
    explicit Kitty(int toys) : m_toys(toys) { }

    void meow(const vector& 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 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 
#include 
#include 
#include 
#include 
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 
#include 
#include 
#include 
#include 
using namespace std;
using namespace std::tr1;

void meow(const vector& v, const functionint)>& 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 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


댓글

이 블로그의 인기 게시물

80040154 오류로 인해 CLSID가 {xxxx-...}인 구성 요소의 COM 클래스 팩터리를 검색하지 못했습니다.

원문보기 .NET 으로 만든 응용프로그램에서 com 객체를 호출한 경우 Windows7 64bit 에서 제목과 같은 에러가 발생했다. Win32 COM 과 .NET 프로그램간의 호환성 때문에 생긴 문제였다. 원인은 .NET 실행시 JIT 컴파일러에 의해 최적화된 기계어로 변환되기 때문.. Win32 COM은 컴파일시.. Win32 COM에 맞춰 빌드 속성에서 하위버전으로 맞춰 컴파일을 다시하는 방법도 있지만 메인 프로젝트가 .NET이라면 참조되는 모든 프로젝트를 다 바꿔야할 노릇.. 또 다른 방법은 COM+를 이용하여 독립적으로 만드는 것이다. 분리시키는 방법은 아래 주소해서 확인할 수 있다. http://support.microsoft.com/kb/281335 나의 경우는 Win32 COM DLL을 64비트 .NET 프로그램에서 참조하니 COM 객체를 제대로 호출하지 못하였습니다. 그래서 .NET 프로그램의 Target Machine을 x86으로 설정하니 제대로 COM 객체를 호출하였습니다.

[Pyinstaller] 실행 파일 관리자 권한 획득하기

고객사에서 일부 사용자에게서 프로그램 오류가 발생한다며 아래와 같이 에러 캡처를 보내왔습니다. 프로그램에서 로그를 남기기 위해 로그 파일을 생성하는데 권한의 문제로 로그 파일을 생성하지 못해 프로그램 오류가 발생한 것 같습니다. 처음에는 Python 코드에서 관리자 권한을 요청하는 코드를 넣으려고 했는데, 실제로 Stackoverflow를 찾아보면 이런 내용이 나옵니다. 프로그램이 관리자 권한으로 실행되지 않았다면 관리자 권한으로 다시 프로그램을 실행시키는 코드입니다. import os import sys import win32com.shell.shell as shell ASADMIN = 'asadmin' if sys.argv[-1] != ASADMIN: script = os.path.abspath(sys.argv[0]) params = ' '.join([script] + sys.argv[1:] + [ASADMIN]) shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params) sys.exit(0) 하지만 개인적으로 이런 방식은 마음에 들지 않았고 조금 더 찾아보니 Pyinstaller로 exe 파일을 만들 때 옵션을 설정하여 관리자 권한을 요청하도록 할 수 있다고 합니다. --uac-admin을 옵션에 추가하면 프로그램 실행 시 관리자 권한을 요청할 수 있습니다. pyinstaller.exe --uac-admin sample.py 하지만 안타깝게도 이 방식은 원하는 대로 동작하지 않았습니다. 마지막으로 manifest 파일을 이용하여 시도해보았습니다. spec 파일을 이용하여 pyinstaller로 빌드하면 <실행 파일 이름>.manifest 라는 파일이 생성됩니다. 파일에서 아랫부분을 찾아볼 수 있습니다. <security> <re

초간단 프로그램 락 걸기

프로그램에 락을 걸 일이 생겨났다. 하드웨어 락을 걸면 쉬울텐데 그 정도는 아니고 프로그램의 실행 날짜를 제한 해 달라고 한다. 그래서 파일(license.lic)을 가지고 락을 걸리고 결정을 했다. 요구 사항은 아래와 같다. 1. license.lic 파일이 없으면 프로그램을 실행 할수 없게 한다. 2. 지정한 날짜를 넘어서는 프로그램을 실행 할수 없게 한다. 3. 사용자가 시스템 날짜를 되돌렸을때 인식하여 프로그램을 실행 할수 없게 한다. 음.... 1.번 문제는 사용자가 프로그램을 실행하기 위해서 license.lic 파일을 받아야만 한다. license.lic 파일에는 최근 실행 날짜/종료날짜 이런식으로 적도록 한다.(물론 내용은 암호화 한다.) 최근 실행날짜는 프로그램이 실행때마다 업데이트 하도록 하고 시스템 날짜와 비교하여 시스템 날짜가 최근 실행 날짜보다 이전의 날짜면 시스템 날짜를 되돌렸다고 인식하도록 한다.(3.번 문제 해결) 시스템 날짜와 종료 날짜를 비교하여 시스템 날짜가 종료 날짜를 넘으면 프로그램을 실행 할수 없도록 한다.(2.번 문제 해결)