일반 람다는 C ++ 14에서 어떻게 작동합니까?


114

autoC ++ 14 표준에서 제네릭 람다는 어떻게 작동합니까 ( 인수 유형으로서의 키워드)?

각기 다른 인수 유형 컴파일러에 대해 동일한 본문이지만 대체 된 유형 (컴파일 시간 다형성)으로 새 함수를 생성하는 C ++ 템플릿을 기반으로합니까? 아니면 Java의 제네릭 (유형 삭제)과 더 유사합니까?

코드 예 :

auto glambda = [](auto a) { return a; };

6
C ++ (14)에 고정 원래의 질문에 C ++ 11을 사용
sasha.sochka

답변:


130

일반 람다가 C++14.

간단하게 람다 식에 의해 정의 된 닫는 방법의 종류는 것이다 템플릿 호출 연산자보다는의 정기적, 비 템플릿 호출 연산자 C++11의 람다 (물론을 때 auto나타납니다 적어도 매개 변수 목록에 한 번).

따라서 귀하의 예 :

auto glambda = [] (auto a) { return a; };

glambda이 유형의 인스턴스를 만듭니다 .

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

C ++ 14 Standard Draft n3690의 5.1.2 / 5 단락은 주어진 람다 식의 클로저 유형에 대한 호출 연산자를 정의하는 방법을 지정합니다.

제네릭이 아닌 람다 식의 클로저 형식에는 매개 변수와 반환 형식이 각각 lambda-expression의 parameter-declaration-clause 및 trailing-return-type으로 설명되는 공용 인라인 함수 호출 연산자 (13.5.4)가 있습니다. 제네릭 람다의 경우 클로저 유형에는 람다의 parameter-declaration-clause에서 auto가 발생할 때마다 template-parameter-list가 하나의 발명 된 type template-parameter로 구성된 공용 인라인 함수 호출 연산자 멤버 템플릿 (14.5.2)이 있습니다. 출현 순으로. 발명 된 유형 템플릿 매개 변수는 해당 매개 변수 선언이 함수 매개 변수 팩 (8.3.5)을 선언하는 경우 매개 변수 팩입니다. 함수 호출 연산자 템플릿의 반환 유형 및 함수 매개 변수는 parameter-declaration-clause의 decl-specifier에서 auto의 각 항목을 다음 이름으로 대체하여 lambda-expression의 후행 반환 유형 및 매개 변수 선언 절에서 파생됩니다. 상응하는 발명 된 템플릿 매개 변수.

드디어:

각기 다른 인수 유형 컴파일러에 대해 동일한 본문이지만 유형이 변경된 함수를 생성하는 템플릿과 유사합니까? 아니면 Java의 제네릭과 더 유사합니까?

위의 단락에서 설명했듯이 일반 람다는 템플릿이 지정된 호출 연산자를 사용하는 고유하고 이름이 지정되지 않은 펑터에 대한 구문 설탕 일뿐입니다. 귀하의 질문에 답해야합니다. :)


7
그러나 템플릿 메서드를 사용하여 로컬로 정의 된 클래스도 허용합니다. 새로운 것입니다.
Yakk-Adam Nevraumont 2013 년

2
@Yakk : 함수 로컬 템플릿에 대한 제한이 이미 C ++ 11과 함께 삭제되지 않았습니까?
Sebastian Mach

2
@phresnel : 아니, 그 제한은 해제되지 않은
앤디 배회

1
@AndyProwl : 나는 내 실수를 깨닫는다. 무슨 일이 (같이 템플릿 인수로 지역 유형을 사용하여 실제로 한 해제 된 int main () { struct X {}; std::vector<X> x; })
세바스찬 마하

1
@phresnel : 참으로 변경되었습니다 오른쪽
앤디 배회

25

불행히도 C ++ 11 ( http://ideone.com/NsqYuq )의 일부가 아닙니다 .

auto glambda = [](auto a) { return a; };

int main() {}

g ++ 4.7 사용 :

prog.cpp:1:24: error: parameter declared auto
...

그러나 일반적인 람다에 대한 포틀랜드 제안에 따라 C ++ 14에서 구현 될 수있는 방법은 다음과 같습니다.

[](const& x, & y){ return x + y; }

이것은 대부분의 경우 익명 펑터 클래스의 일반적인 생성을 산출하지만 유형이 부족하면 컴파일러가 템플릿 멤버를 내 보냅니다 operator().

struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};

또는 Generic (Polymorphic) Lambda Expressions에 대한 새로운 제안 제안에 따라

auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;

그렇습니다. 매개 변수의 모든 순열에 대해 새로운 인스턴스화가 발생하지만 해당 펑터의 멤버는 여전히 공유됩니다 (즉, 캡처 된 인수).


6
유형 지정자를 삭제하는 것을 허용하는 그 제안 은 완전히 기괴합니다.
궤도의 가벼운 경주

그들은 g ++-4.9들어 갔습니다 . 를 제공해야합니다 -std=c++1y.
emsr 2013 년

나는 ideone에 아직 gcc-4.9와 C ++ 14가 없다는 것을 몰랐습니다.
emsr 2014 년

질문 : 이것은 auto클래식 자동차와 동일한 공제 규칙을 가지고 있습니까? 템플릿 비유를 참조하면 자동이 자동이 아니라 템플릿 유형 추론과 동일한 규칙을 의미합니다. 그러면 질문은 다음과 같습니다. 템플릿 공제는 다음과 동일 auto합니까?
v.oddou

@ v.oddou : "클래식 자동"이 좋습니다. 나에게 "클래식 자동"은 "스택 변수"를 의미하며, static또는 register:) 와는 대조적으로 사용 된 적이 있습니다. 어쨌든, 그렇습니다. auto거기 사용 한다는 것은 내부적으로 일반 템플릿이 생성된다는 것을 의미합니다. 사실, 람다는 컴파일러 내부에서 functor 클래스로 대체 될 것이며, auto매개 변수는 그것이 template <T> ... (T ...)방출 된다는 것을 의미합니다 .
세바스찬 마하

17

템플릿과 비슷하거나 동등한 제안 된 C ++ 14 기능 (C ++ 11에는 없음)입니다. 예를 들어 N3559 는 다음 예를 제공합니다.

예를 들어 다음과 같은 일반적인 람다 식 포함 문 :

auto L = [](const auto& x, auto& y){ return x + y; };

클로저 유형과 아래 구조체와 유사하게 동작하는 객체가 생성 될 수 있습니다.

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.