람다 함수를 템플릿으로 만들 수 있습니까?


230

C ++ 11에는 람다 함수를 템플릿으로 만드는 방법이 있습니까? 아니면 템플릿으로 지정하기에는 너무 구체적입니까?

나는 대신 고전적인 템플릿 클래스 / functor를 정의 할 수 있다는 것을 이해하지만 질문은 더 비슷합니다 : 언어가 람다 함수를 템플릿 할 수 있습니까?


람다 템플릿이 유용한 유스 케이스가 있습니까?
James McNellis

7
제임스 : 튜플을 반복하는 함수를 만들 수 있습니다 (반드시 유용한 것은 아닙니다).
Joe D

메타 템플릿 복잡성에 대한 이야기를하는 Stroustrup의 인터뷰를 읽는 동안 아이디어를 생각했습니다. 그것이 허용된다면, 나는이 기능 조합을 가지고 노는 너무 영리한 프로그래머에 의해 발명 될 수있는 닌자 코드
푸를

답변:


181

업데이트 2018 : C ++ 20에는 템플릿 및 개념화 된 람다가 함께 제공됩니다. 이 기능은 이미 표준 초안에 통합되었습니다.


업데이트 2014 : C ++ 14가 올해 출시되었으며 이제이 예제와 동일한 구문으로 다형성 람다를 제공합니다. 일부 주요 컴파일러는 이미이를 구현합니다.


그것은 C ++ 11에서 슬프게도 아닙니다. 다형성 람다는 유연성과 힘면에서 우수합니다.

그들이 단일 형태가 된 최초의 이유는 개념 때문이었습니다. 개념으로 인해이 코드 상황이 어려워졌습니다.

template <Constraint T>
void foo(T x)
{
    auto bar = [](auto x){}; // imaginary syntax
}

제한된 템플릿에서는 다른 제한된 템플릿 만 호출 할 수 있습니다. (그렇지 않으면 제약 조건을 확인할 수 없습니다.) foo호출 할 수 있습니까 bar(x)? 람다에는 어떤 제약 조건이 있습니까 (매개 변수는 템플릿 일뿐입니다)?

개념은 이런 종류의 일을 다룰 준비가되지 않았습니다. 그것은 late_check(개념이 호출 될 때까지 확인되지 않은) 더 많은 것들을 필요 로합니다. 더 간단하게 모든 것을 버리고 단일 람다에 충실하는 것이 었습니다.

그러나 C ++ 0x에서 개념을 제거하면 다형성 람다는 간단한 제안이됩니다. 그러나 이에 대한 제안을 찾을 수 없습니다. :(


5
간단합니다. 개념을 다시 도입하고 개념을 복잡하게 만드는 기능을 피하려는 욕구가 있습니다.

6
나는 개념보다 다형성 람다를 원한다고 생각합니다. 나는 그 모범이 어떻게 동기를 부여하는지 이해하지 못한다. 오류로 간단히 금지 할 수 있으며 람다는 monomorphic [] (T x) {} 또는 제한된 템플릿 [] template <Constraint T> (T x) {}이어야하며, 정적으로 일치하는지 확인할 수 있습니다. 이것이 불가능한 이유가 있습니까?
DrPizza

13
개념과 다형성 람다 중에서 선택할 필요는 없습니다. cpp-next.com/archive/2011/12/a 획기적인
Dave Abrahams

3
다음은 다형성 람다에 대한 제안입니다 : open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3418.pdf 및 clang의 장난감 구현 : faisalv.github.com/clang-glambda
Radia Sharafullin

18
다형성 주면서 적어도 그들은 :) 지금 커뮤니티 초안에, C ++ 14에있을 것입니다
아르네 메츠

37

C ++ 11 람다는 다른 답변에서 설명한대로 템플릿을 만들 수 없지만 decltype()템플릿 클래스 또는 함수 내에서 람다를 사용할 때 도움이되는 것으로 보입니다.

#include <iostream>
#include <string>

using namespace std;

template<typename T>
void boring_template_fn(T t){
    auto identity = [](decltype(t) t){ return t;};
    std::cout << identity(t) << std::endl;
}

int main(int argc, char *argv[]) {
    std::string s("My string");
    boring_template_fn(s);
    boring_template_fn(1024);
    boring_template_fn(true);
}

인쇄물:

My string
1024
1

이 기술은 템플릿 코드로 작업 할 때 도움이되지만 여전히 람다 자체를 템플릿으로 만들 수 없다는 것을 알고 있습니다.


26
Tdecltype(t)이 예제 대신 잘 작동합니다 .
user2023370

26

C ++ 11에서는 람다 함수를 템플릿으로 만들 수 없지만 다음 버전의 ISO C ++ 표준 (일반적으로 C ++ 14)에서는이 기능이 도입됩니다. [출처]

사용 예 :

auto get_container_size = [] (auto container) { return container.size(); };

구문에서 keyword를 사용하지만 auto유형 공제는 유형 공제 규칙을 사용하지 auto않고 대신 템플리트 인수 공제 규칙을 사용합니다. 또한 일반적인 람다 식 제안 (및 이에 대한 업데이트) 을 참조하십시오 .


5
auto유형 공제 규칙은 template함수 인수 공제 규칙과 동일하게 정의됩니다 .
underscore_d

10

이 질문이 C ++ 11에 관한 것임을 알고 있습니다. 그러나이 페이지에 Google을 방문하고 방문한 사람들에게는 템플릿 람다가 C ++ 14에서 지원되며 Generic Lambdas라는 이름으로 사용됩니다.

[info] 널리 사용되는 대부분의 컴파일러는 현재이 기능을 지원합니다. Microsoft Visual Studio 2015가 지원됩니다. Clang이 지원합니다. GCC가 지원합니다.


6

나는 이것에 대해 궁금합니다.

template <class something>
inline std::function<void()> templateLamda() {
  return [](){ std::cout << something.memberfunc() };
}

비슷한 코드를 사용하여 템플릿을 생성하고 컴파일러가 "래핑"기능을 최적화하는지 궁금합니다.


2
어떤 컴파일러? 그것을했다?
NicoBerrogorry


3

람다 템플릿 을 허용 하는 gcc 확장 이 있습니다 .

// create the widgets and set the label
base::for_each(_widgets, [] <typename Key_T, typename Widget_T>
                         (boost::fusion::pair<Key_T, Widget_T*>& pair) -> void {
                             pair.second = new Widget_T();
                             pair.second->set_label_str(Key_T::label);
                          }
              );

어디 _widgets있어std::tuple< fusion::pair<Key_T, Widget_T>... >


FWIW, 이것은 C ++ 20에서 표준 구문이되었습니다.
LF

2

나는 플래그로 version 5.0.1컴파일 하는 최신 clang을 가지고 놀고 -std=c++17있었고 이제 람다에 대한 자동 유형 매개 변수에 대한 훌륭한 지원이 있습니다.

#include <iostream>
#include <vector>
#include <stdexcept>

int main() {
    auto slice = [](auto input, int beg, int end) {
        using T = decltype(input);
        const auto size = input.size();
        if (beg > size || end > size || beg < 0 || end < 0) {
            throw std::out_of_range("beg/end must be between [0, input.size())");
        }
        if (beg > end) {
            throw std::invalid_argument("beg must be less than end");
        }
        return T(input.begin() + beg, input.begin() + end);
    };
    auto v = std::vector<int> { 1,2,3,4,5 };
    for (auto e : slice(v, 1, 4)) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}

1

다음은 람 바를 구조로 감싸는 솔루션입니다.

template <typename T>                                                   
struct LamT                                                             
{                                                                       
   static void Go()                                                     
   {                                                                    
      auto lam = []()                                                   
      {                                                                 
         T var;                                                         
         std::cout << "lam, type = " << typeid(var).name() << std::endl;
      };                                                                

      lam();                                                            
   }                                                                    
};   

사용하려면 :

LamT<int>::Go();  
LamT<char>::Go(); 
#This prints 
lam, type = i
lam, type = c

이것에 대한 주요 문제 (추가 타이핑 제외)는이 구조 정의를 다른 메소드에 포함시킬 수 없거나 얻을 수 없습니다 (gcc 4.9)

error: a template declaration cannot appear at block scope

나는 또한 이것을 시도했다 :

template <typename T> using LamdaT = decltype(                          
   [](void)                                                          
   {                                                                 
       std::cout << "LambT type = " << typeid(T).name() << std::endl;  
   });

다음과 같이 사용할 수 있기를 바랍니다.

LamdaT<int>();      
LamdaT<char>();

그러나 컴파일러 오류가 발생합니다.

error: lambda-expression in unevaluated context

그래서 이것은 작동하지 않습니다 ...하지만 컴파일 된 경우에도 "LamdaT 사용"을 파일 범위 (템플리트이기 때문에)에 배치해야하기 때문에 사용이 제한적입니다. 람다.


1

왜 아무도 이것을 제안하지 않았는지 모르겠지만 람다 함수를 반환하는 템플릿 함수를 작성할 수 있습니다. 다음은 내 문제,이 페이지에 온 이유를 해결했습니다.

template <typename DATUM>
std::function<double(DATUM)> makeUnweighted() {
  return [](DATUM datum){return 1.0;};
}

이제 주어진 유형의 인수를 취하는 함수를 원할 때마다 (예 : std::string ), 난 그냥 말

auto f = makeUnweighted<std::string>()

그리고 지금 f("any string") 반환합니다 1.0.

이것이 "템플릿 된 람다 함수"의 의미에 대한 예입니다. (이 특별한 경우는 데이터에 관계없이 누군가가 데이터에 가중치를 부여하지 않으려는 경우 자동으로 비활성 가중치 기능을 제공하는 데 사용됩니다.)


2
이것은 람다를 만들기 전에 람다에 대한 인수의 유형을 알고있는 경우에만 작동합니다.이 경우 특정 유형의 람다를 인수로 사용할 수 있습니다. 다형성 람다의 요점은 작업 코드를 작성할 때 알 수없는 인수 유형에서 수행 할 작업을 제공하는 것입니다. 기본적으로 이것은 완전히 다르기 때문에 제안되지 않았습니다.
클라 임

아 맞아. 나는 그 사용 사례를 생각하지 않았다. 나는 람다 함수를 즉시 사용하는 것으로 생각하고 그런 다형성은 다목적 라이브러리의 어떤 것으로 생각한다. 모든 유형의 사용자 람다 함수를 수락하고 올바른 유형의 기본값을 제공 해야하는 템플릿 라이브러리를 작성 중이었습니다.
Jim Pivarski
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.