C ++ 11에서 같은 유형의 람다 벡터를 만들 수없는 이유는 무엇입니까?


89

람다 벡터를 만들려고했지만 실패했습니다.

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

라인 # 2까지 잘 컴파일됩니다 . 그러나 줄 # 3은 컴파일 오류를 제공 합니다 .

오류 : 'std :: vector <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)'호출에 일치하는 함수가 없습니다.

함수 포인터의 벡터 나 함수 객체의 벡터를 원하지 않습니다. 그러나 실제 람다 식 을 캡슐화하는 함수 객체의 벡터는 저에게 효과적입니다. 이것이 가능한가?


23
"나는 함수 포인터의 벡터 나 함수 객체의 벡터를 원하지 않습니다." 그러나 그것은 당신이 요청한 것입니다. 람다 함수 객체입니다.
Nicol Bolas 2011 년

답변:


136

모든 람다는 서명이 동일하더라도 유형이 다릅니다 . 이와 같은 std::function작업을 수행하려는 경우 와 같이 런타임 캡슐화 컨테이너를 사용해야합니다.

예 :

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

52
백 남자 개발자 팀을 관리하는 것은 더 악몽 같은 : 나에게 소리
제레미 Friesner

10
또한, 캡처없는 람다 ([] 스타일)는 함수 포인터로 저하 될 수 있음을 잊지 마십시오. 따라서 그는 동일한 유형의 함수 포인터 배열을 저장할 수 있습니다. VC10은 아직이를 구현하지 않습니다.
Nicol Bolas 2011 년

그건 그렇고, 어쨌든 그 예제에서 캡쳐리스를 사용해서는 안됩니까? 아니면 필요합니까? -그런데, 함수 포인터에 대한 캡쳐리스 람다는 VC11에서 지원되는 것 같습니다. 그래도 테스트하지 않았습니다.
Klaim 2011 년

2
다른 유형의 함수를 저장하는 벡터를 만들 수 있습니까? 즉,로 제한하는 대신 std::function<int()다른 함수 프로토 타입을 사용할 수 있습니까?
manatttta 2015 년

2
@manatttta 요점은 무엇입니까? 컨테이너는 동일한 유형의 개체를 저장하고 함께 구성 및 조작하기 위해 존재합니다. ' vector저장소 std::function와 둘 다 만들 수 std::string있습니까?' 라고 물어 보는 것이 좋습니다. 그리고 대답은 동일합니다. 아니요, 의도 된 용도가 아니기 때문입니다. '변형'스타일의 클래스를 사용하여 컨테이너에 이질적인 것을 넣을 수있는 충분한 유형 삭제를 수행 할 수 있으며, 사용자가 '실제'유형을 결정하여 무엇을 할 것인지 (예 : 호출 방법) 선택할 수있는 메서드를 포함 할 수 있습니다. 각 요소 ...하지만 다시, 왜 그런 길이로 가나 요? 진짜 근거가 있습니까?
underscore_d

41

모든 람다 식은 문자별로 동일한 경우에도 유형이 다릅니다 . 다른 유형의 람다 (다른 표현식이기 때문에)를 벡터에 밀어 넣고 있는데 분명히 작동하지 않습니다.

한 가지 해결책std::function<int()>대신 벡터를 만드는 것입니다.

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

또 다른 참고로, [&]아무것도 캡처하지 않을 때 사용하는 것은 좋은 생각 이 아닙니다.


14
()인수를 취하지 않는 람다가 필요하지 않습니다 .
Puppy

18

다른 사람들이 말한 내용은 관련이 있지만 람다 벡터를 선언하고 사용할 수는 있지만 그다지 유용하지는 않습니다.

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

따라서 lambda! 의 복사 / 이동 인 한 거기에 원하는 수의 람다를 저장할 수 있습니다 .


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

7
이 같은 람다의 모든 사본과 벡터 것이다 그래서 당신은 ... 벡터, 단지 함수 객체의 매개 변수를 넣지 마십시오
hariseldon78

16

람다가 상태 비 저장 인 경우, 즉, [](...){...}C ++ 11을 사용하면 함수 포인터로 저하 될 수 있습니다. 이론적으로 C ++ 11 호환 컴파일러는 다음을 컴파일 할 수 있습니다.

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

4
공식적으로 auto ignore = *[] { return 10; };만들 것 ignoreint(*)().
Luc Danton

1
@Luc, 오 그거 엄청나 네요! 언제 추가 했나요?
MSN

3
음, 처음에 함수 포인터를 사용할 수있는 변환 함수는이어야하기 때문에 explicit람다 식을 역 참조하는 것이 유효하며 변환 결과 포인터를 역 참조합니다. 그런 다음 auto포인터로 다시 참조 하는 감쇠를 사용 합니다. (사용 auto&또는 auto&&참조를 유지 한 것이다.)
루크 달톤

아 ... 결과 포인터를 역 참조합니다. 말이 되네요. 누락 된 ()것이 의도적입니까, 우연적입니까?
MSN

의도적으로 람다 식은 동일하지만 두 문자가 더 짧습니다.
Luc Danton 2011 년

6

람다 생성 함수를 사용할 수 있습니다 (Nawaz에서 제안한 수정 사항으로 업데이트 됨).

#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 등이 있으면 튜플을 사용해야 할 것입니다.


lambda_gen차례로 람다 자체가 될 수 있는 함수로 래핑하는 것이 좋습니다 . 그러나 auto a = lambda_gen(1);불필요한 호출을하므로 이것을 작성하면 피할 수 있습니다 decltype(lambda_gen(1)).
Nawaz

그래도 여전히 추가 전화가 걸리지 않습니까? 또한 또 다른 사소한 점은 질문에 C ++ 11이라고 나와 있으므로 내가 생각하는 함수에 후행 반환 유형을 추가해야한다는 것입니다.
antediluvian

아니요. 내부 항목 decltype평가되지 않으므로 실제로 통화가 이루어지지 않습니다. 그것도 sizeof마찬가지입니다. 또한이 코드는 후행 반환 유형을 추가하더라도 C ++ 11에서 작동하지 않습니다 !!
Nawaz

4

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.