람다 식을 반환하는 함수


88

C ++ 11에서 람다 함수를 반환하는 함수를 작성할 수 있는지 궁금합니다. 물론 한 가지 문제는 이러한 기능을 선언하는 방법입니다. 각 람다에는 유형이 있지만 해당 유형은 C ++에서 표현할 수 없습니다. 이것이 효과가 있다고 생각하지 않습니다.

auto retFun() -> decltype ([](int x) -> int)
{
    return [](int x) { return x; }
}

이것도 :

int(int) retFun();

람다에서 함수에 대한 포인터 등으로의 자동 변환을 알지 못합니다. 유일한 솔루션은 함수 객체를 직접 만들고 반환합니까?


1
이미 말한 내용을 추가하려면 상태 비 저장 람다 함수를 함수 포인터로 변환 할 수 있습니다.
snk_kid 2011 년

3
IMO에서 람다가 decltype함수 본문에서와 같지 않아서 다른 유형을
갖기

1
그런데 람다에 빈 캡처 절이있는 경우 암시 적으로 함수에 대한 포인터로 변환 할 수 있습니다.
GManNickG 2011 년

@GMan : Visual C ++ 2010 또는 약 1 년 이상 전에 출시 된 g ++ 버전을 사용하지 않는 한. 함수 포인터로의 캡처없는 람다 암시 적 변환은 N3092에서 2010 년 3 월까지 추가되지 않았습니다.
James McNellis 2011 년

4
일반적으로 람다 식은 평가되지 않은 피연산자에 나타날 수 없습니다. 그래서 decltype([](){})또는 sizeof([]() {})당신이 그것을 어디에 쓰든 상관없이 형식이 잘못되었습니다.
Johannes Schaub-litb

답변:


98

직접 만든 함수 객체가 필요하지 않고 std::function람다 함수를 변환 할 수있는를 사용 하면됩니다.

이 예는 정수 식별 함수를 반환합니다.

std::function<int (int)> retFun() {
    return [](int x) { return x; };
}

6
야! 저는 StackOverflow를 좋아합니다. 주제를 조사하고 StackOverflow에 대한 답변을 얻는 데 훨씬 더 오래 걸렸을 것입니다. 감사합니다 Sean!
Bartosz Milewski 2011 년

6
의 생성자에서 메모리 할당이 발생합니다 std::function.
Maxim Egorushkin 2011 년

2
@Maxim Yegorushkin std :: function에는 이동 의미 체계가 있으며 사용자 지정 할당자를 사용할 수 있으며 C ++ 0x 작업 초안에 다음과 같은 메모가 있습니다. "[참고 : 구현은 작은 호출 가능 개체에 대해 동적으로 할당 된 메모리를 사용하지 않도록 권장됩니다. 예를 들어 , 여기서 f의 타겟은 객체에 대한 포인터 또는 참조와 멤버 함수 포인터 만 보유하는 객체입니다. —end note] "따라서 기본적으로 특정 구현이 사용하는 할당 전략에 대해 많은 가정을 할 수는 없지만 가능해야합니다. 어쨌든 자신의 (풀링 된) 할당자를 사용합니다.
snk_kid 2011 년

1
@Maxim : 내 대답은 "함수 개체를 직접 만들고 반환하는 유일한 솔루션입니까?"라는 질문에 대한 것이 었습니다.

2
std::function유형 삭제 를 사용 한다는 점을 명심하십시오. 이는 .NET을 호출 할 때 가상 함수 호출 비용을 의미 할 수 있습니다 std::function. 반환 된 함수가 타이트한 내부 루프 또는 약간의 비 효율성이 중요한 다른 컨텍스트에서 사용될 경우 알아야 할 사항입니다.
Anthony Hall

29

이 간단한 예에서는 std::function.

표준 §5.1.2 / 6에서 :

A의 폐쇄 형 람다 표현 아니오 람다 캡처는 폐쇄 형의 함수 호출 연산자와 같은 매개 변수와 리턴 유형을 가진 함수 포인터에 공개되지 않은 가상이 아닌 명시 적 const를 변환 기능이 있습니다. 이 변환 함수에 의해 반환 된 값은 호출 될 때 클로저 유형의 함수 호출 연산자를 호출하는 것과 동일한 효과를 갖는 함수의 주소 여야합니다.

함수에 캡처가 없기 때문에 람다를 다음 형식의 함수에 대한 포인터로 변환 할 수 있습니다 int (*)(int).

typedef int (*identity_t)(int); // works with gcc
identity_t retFun() { 
  return [](int x) { return x; };
}

그것이 내 이해입니다. 내가 틀렸다면 나를 바로 잡으십시오.


1
이거 맞아. 불행히도 내가 사용하고있는 현재 컴파일러에서는 작동하지 않습니다 : VS 2010. std :: function 변환이 작동합니다.
Bartosz Milewski 2011 년

3
예,이 규칙의 최종 문구는 VC2010에 너무 늦었습니다.
Ben Voigt 2011

코드 예제를 추가했습니다. 다음은 전체 프로그램 입니다.
jfs

@JFSebastian-이 예제에서 람다의 수명은 얼마입니까? 함수 포인터로의 변환 결과보다 오래 지속됩니까?
Flexo

1
@JFSebastian-이에 대한 답을 찾을 수없는 것 같아서 자체적으로 질문을했습니다. stackoverflow.com/questions/8026170/…
Flexo

21

람다 함수의 반환 유형을 명시 적으로 지정해서는 안되므로 다른 람다 함수에서 람다 함수를 반환 할 수 있습니다. 전역 범위에서 다음과 같이 작성하십시오.

 auto retFun = []() {
     return [](int x) {return x;};
 };

2
외부 람다가 return 문으로 만 구성된 경우에만 해당됩니다. 그렇지 않으면 반환 유형을 지정해야합니다.
Bartosz Milewski 2011

3
std :: function의 런타임 다형성이 필요하지 않고 람다가 비어 있지 않은 캡처 목록을 가질 수 있기 때문에 이것이 가장 좋은 대답입니다. 그러나 저는 const auto fun = ...을 사용합니다 .
robson3.14

2
@BartoszMilewski는 C ++ 14 이후로 사실이 아닙니다.
dzhioev

19

이 질문은 C ++ 11에 대해 구체적으로 묻지 만,이를 우연히 발견하고 C ++ 14 컴파일러에 액세스 할 수있는 다른 사용자를 위해 C ++ 14는 이제 일반 함수에 대해 추론 된 반환 유형을 허용합니다. 따라서 질문의 예 -> decltype는 함수 매개 변수 목록 뒤에 ... 절 을 삭제하여 원하는대로 작동하도록 조정할 수 있습니다 .

auto retFun()
{
    return [](int x) { return x; }
}

그러나 return <lambda>;함수에 둘 이상이 나타나면 작동하지 않습니다 . 반환 형식 추론에 대한 제한은 모든 반환 문이 동일한 형식의 식을 반환해야하지만 모든 람다 개체에는 컴파일러에 의해 고유 한 형식이 지정되므로 return <lambda>;식이 각각 다른 형식을 갖기 때문입니다.


4
C ++ 14의 추론 된 유형을 언급하지만 다형성 람다를 생략하는 이유는 무엇입니까? auto retFun() { return [](auto const& x) { return x; }; }
sehe

1

다음과 같이 작성해야합니다.

auto returnFunction = [](int x){
    return [&x](){
        return x;
    }();
};

반환을 함수로 가져오고 다음과 같이 사용하십시오.

int val = returnFunction(someNumber);

0

예를 들어 C ++ 11이없고 마이크로 컨트롤러에서 C ++ 코드를 실행하는 경우. void 포인터를 반환 한 다음 캐스트를 수행 할 수 있습니다.

void* functionThatReturnsLambda()
{
    void(*someMethod)();

    // your lambda
    someMethod = []() {

        // code of lambda

    };

    return someMethod;
}


int main(int argc, char* argv[])
{

    void* myLambdaRaw = functionThatReturnsLambda();

    // cast it
    auto myLambda = (void(*)())myLambdaRaw;

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