2011-09-19 2 views
70

나는 람다의 벡터를 만들려고하지만 실패했습니다 :C++ 11에서 (동일한 유형의) 람다 벡터를 만들 수없는 이유는 무엇입니까?

auto ignore = [&]() { return 10; }; //1 
std::vector<decltype(ignore)> v;  //2 
v.push_back([&]() { return 100; }); //3 

업 # 2 행으로, compiles fine을. 그러나 라인 # 3 compilation error을 제공합니다

error: no matching function for call to 'std::vector<main()::<lambda()>>::push_back(main()::<lambda()>)'

나는 함수 포인터 또는 함수 객체의 벡터의 벡터를 원하지 않는다. 그러나 실제 람다 식을 캡슐화하는 함수 객체의 벡터가 나를 위해 작동합니다. 이것이 가능한가?

+21

"기능 포인터 벡터 나 기능 개체 벡터가 필요 없습니다." 그러나 그것이 당신이 요구 한 것입니다. 람다 **는 ** 함수 객체입니다. –

+0

밀접하게 관련 : [C++ 11에서 "auto"로 추론 할 때 람다 유형은 무엇입니까?] (http://stackoverflow.com/q/7951377/514235). – iammilind

답변

112

모든 람다는 동일한 서명이 있어도 — 인 경우 입니다. 이런 일을하고 싶다면 std::function과 같은 런타임 캡슐화 컨테이너를 사용해야합니다.

예 :은 :

std::vector<std::function<int()>> functors; 
functors.push_back([&] { return 100; }); 
functors.push_back([&] { return 10; }); 

I don't want a vector of function pointers or vector of function objects.

글쎄, 난 내 모든 꿈을 개발하는 수백 명의 개발자 팀과 함께 좋은 높은 지불하는 작업을하고 싶지만, 그 거 하나, 일이 아닙니다. 항상 원하는 것을 얻을 수는 없습니다.

+51

백 명의 개발자 팀을 관리하는 것이 나에게 악몽처럼 들립니다. –

+10

또한, 캡쳐가없는 람다 ([] 스타일)가 기능 포인터로 저하 될 수 있음을 잊지 마십시오. 따라서 그는 동일한 유형의 함수 포인터 배열을 저장할 수 있습니다. VC10은 아직 구현하지 않았습니다. –

+0

그건 그렇고, 어쨌든 그 예들에서 캡쳐리스를 사용해서는 안됩니다. 아니면 필요한가요? - 그런데 VC11에서는 캡쳐리스 람다 함수 포인터가 지원되는 것 같습니다. 비록 그것을 테스트하지 않았다. – Klaim

36

모든 람다식이 동일한 문자 (문자 :) 인 경우에도 이 다릅니다. 다른 유형의 람다를 벡터에 넣기 때문에 분명히 작동하지 않습니다.

One solutionstd::function<int()>의 벡터를 대신 작성해야합니다. 다른 주에

auto ignore = [&]() { return 10; }; 
std::vector<std::function<int()>> v; 
v.push_back(ignore); 
v.push_back([&]() { return 100; }); 

, 그것은 아무것도 촬영하지 않을 때 [&]을 사용하는 것이 좋습니다 아니다.

+8

인수를 취하지 않는 lambdas에는'()'이 필요 없습니다. – Puppy

12

람다가 무 상태 (예 : [](...){...}) 인 경우 C++ 11에서는 함수 포인터로 변환 할 수 있습니다. 이론적으로는 C++ (11)을 준수 컴파일러는이를 컴파일 할 수있을 것입니다 :

auto ignore = []() { return 10; }; //1 note misssing & in []! 
std::vector<int (*)()> v;  //2 
v.push_back([]() { return 100; }); //3 
+3

레코드'auto ignore = * [] {return 10; };'는'int (*)()'를 무시합니다. –

+0

@Luc, 오 그 총입니다! 그들은 언제 그것을 추가 했습니까? – MSN

+2

글쎄, 처음부터 함수 포인터를 가져 오는 것을 허용하는 변환 함수는'explicit'이 아니기 때문에, 람다 식을 역 참조하는 것이 유효하고 변환 결과로 나온 포인터를 역 참조합니다. 그런 다음 '자동'을 사용하여 해당 참조를 포인터로 되돌립니다. ('auto &'또는'auto && '를 사용하면 참조가 유지됩니다.) –

17

관련 어떤 다른 사람이 말했다, 매우 유용하지 비록, 선언하고 람다의 벡터를 사용하는 것이 여전히 가능하지만 :

auto lambda = [] { return 10; }; 
std::vector<decltype(lambda)> vector; 
vector.push_back(lambda); 

그래서, 당신은 너무 오래가 lambda의 복사/이동이의로, 거기에 람다의 수를 저장할 수 있습니다!

+0

푸시 백이 다른 매개 변수가있는 루프에서 발생하는 경우 실제로 유용 할 수 있습니다. 아마도 게으른 평가 목적 때문일 것입니다. – MaHuJa

+6

아니, 당신은 벡터에 매개 변수를 넣지 않아요, 그냥 함수 객체 .. 그래서 같은 람다의 모든 복사본을 가진 벡터가 될 것입니다 – hariseldon78

2

각 람다는 다른 유형입니다. std::vector 대신 std::tuple을 사용해야합니다.

2

당신은 람다 발생 기능 (나와 즈가 제안한 수정 업데이트) 사용할 수 있습니다

#include <vector> 
#include <iostream> 

int main() { 
    auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ; 

    using my_lambda = decltype(lambda_gen(1)); 

    std::vector<my_lambda> vec; 

    for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i)); 

    int i = 0; 

    for (auto& lambda : vec){ 
     std::cout << lambda(i) << std::endl; 
     i++; 
    } 
} 

을하지만 난 당신이 기본적으로이 시점에서 자신의 클래스를 만들 생각합니다. 그렇지 않으면 람다가 완전히 다른 caputres/args 등이 있다면 아마도 튜플을 사용해야합니다.

+0

'lambda_gen'과 같은 함수로 이것을 감쌀 수 있습니다. 람다 그 자체. 그러나,'auto a = lambda_gen (1);'은 불필요한 호출을합니다. 이것은 우리가 ['decltype (lambda_gen (1))'이라고 쓰면 피할 수 있습니다 (http://coliru.stacked-crooked.com/a/27c315671c196a56). – Nawaz

+0

그래도 추가 전화가 걸립니까? 또한 또 다른 사소한 점은 질문에 C++ 11이 있다고 생각하기 때문에 생각하는 함수에 후행 형을 추가해야 할 필요가 있습니다. – antediluvian

+0

아니요.'decltype' 안에있는 것은 아무 것도 평가되지 않습니다. 따라서 실제로 호출되지 않습니다. 'sizeof'와 같은 경우입니다. 또한,이 코드는 C++ 11에서 작동하지 않을 것이다. – Nawaz

관련 문제