람다를 받아들이는 함수를 선언하는 방법은 무엇입니까?


82

인터넷에서 표준 라이브러리 (예 :)와 함께 람다를 사용하는 방법을 설명하는 많은 자습서를 읽었으며 std::find모두 매우 흥미로 웠지만 내 함수에 람다를 사용하는 방법을 설명하는 자습서를 찾을 수 없었습니다.

예를 들면 :

int main()
{
    int test = 5;
    LambdaTest([&](int a) { test += a; });

    return EXIT_SUCCESS;
}

어떻게 신고해야 LambdaTest합니까? 첫 번째 인수의 유형은 무엇입니까? 그런 다음 익명 함수를 어떻게 호출 할 수 있습니까? 예를 들어 "10"을 인수로 전달할 수 있습니까?

답변:


78

람다 외에 함수 포인터와 함수 객체도 허용하려는 경우 템플릿을 사용하여 operator(). 이것은 find와 같은 표준 함수가하는 일입니다. 다음과 같이 표시됩니다.

template<typename Func>
void LambdaTest(Func f) {
    f(10);
}

이 정의는 C ++ 0x 기능을 사용하지 않으므로 완전히 이전 버전과 호환됩니다. C ++ 0x와 관련된 람다 식을 사용하는 함수에 대한 호출 일뿐입니다.


2
오류의 경우 오류 메시지를 이해하기 어렵습니다.
liori

13
그것이 최고인지 여부에 달려 있습니다. 이것은 템플릿을 사용하고 다른 하나는 사용하지 않습니다. 즉, 함수는 더 이상 가상이 될 수 없으며 cpp 파일에서 별도로 정의 할 수 없습니다. std::function함수 객체 클래스 유형도 완벽하게 사용할 수 있지만 호출 할 때 약간 느립니다. 그러나 그 차이는 대부분의 응용 프로그램에서 무시할 수 있습니다. :)
Johannes Schaub-litb

2
"최고"는 보는 사람의 눈에 있습니다. :-)이 대답 functor은 좋은 것을 사용 하지만 "내 기능에 람다를 사용하는 방법"이라는 원래 질문에 실제로 대답하지 않습니다. . 또한 템플릿에는 자체 문제 집합이 있지만 답변 std::function에는 없습니다.
Marco Massenzio 2017

1
@Marco이 답변은 functior를 사용할 필요가 없으며 람다를 포함하여 원하는 것을 사용할 수 있습니다.
sepp2k apr

68

모든 항목을 템플릿으로 지정하지 않으려면 다음을 수행 할 수 있습니다.

void LambdaTest (const std::function <void (int)>& f)
{
    ...
}

1
이 구문을 사용하면 나중에 호출 할 함수 변수를 저장할 수 있습니다. 예를 들어 람다가 콜백 역할을하는 비동기 데이터베이스 쿼리를 실행할 수있는 함수를 구현하고 싶었습니다. (물론 참조로 클로저에 액세스 할 수 없습니다)
Thomas Bonini

1
값으로 함수를 전달하는 것이 더 관용적이지 않습니까?
fredoverflow

1
@Andreas Bonini : 예, std::function(참조가 아님)에 저장하면 f. 그러나 참조 된 객체가 아마도 UB 범위를 벗어날 때 람다 / 클로저가 참조를 처리하는 방법을 잘 모르겠습니다. @FredOverflow : 내 이해는 std::function특히 람다를 래핑 할 때 사소한 개체가 아니라는 것입니다. 불필요한 복사를 피하기 위해 참조하는 것이 좋습니다.

람다가 값으로 스택을 캡처하면 람다는 해당 변수보다 오래 지속될 수 있으며 계속해서 복사본을 유지할 것입니다. 참조로 캡처하면 문제가 발생합니다.
Kate Gregory

1
함수 내에서 복사해야하므로 전달 될 때 복사 할 필요가 없습니다.
Casebash

9

이 간단하지만 자명 한 예제를 제공하고 싶습니다. "호출 가능한 것"(함수, 함수 객체 및 람다)을 함수 또는 객체에 전달하는 방법을 보여줍니다.

// g++ -std=c++11 thisFile.cpp

#include <iostream>
#include <thread>

using namespace std;

// -----------------------------------------------------------------
class Box {
public:
  function<void(string)> theFunction; 
  bool funValid;

  Box () : funValid (false) { }

  void setFun (function<void(string)> f) {
    theFunction = f;
    funValid = true;
  }

  void callIt () {
    if ( ! funValid ) return;
    theFunction (" hello from Box ");
  }
}; // class

// -----------------------------------------------------------------
class FunClass {
public:
  string msg;
  FunClass (string m) :  msg (m) { }
  void operator() (string s) {
    cout << msg <<  s << endl; 
  }
};

// -----------------------------------------------------------------
void f (string s) {
  cout << s << endl;
} // ()

// -----------------------------------------------------------------
void call_it ( void (*pf) (string) ) {
  pf( "call_it: hello");
} // ()

// -----------------------------------------------------------------
void call_it1 ( function<void(string)> pf ) {
  pf( "call_it1: hello");
} // ()

// -----------------------------------------------------------------
int main() {

  int a = 1234;

  FunClass fc ( " christmas ");

  f("hello");

  call_it ( f );

  call_it1 ( f );

  // conversion ERROR: call_it ( [&] (string s) -> void { cout << s << a << endl; } );

  call_it1 ( [&] (string s) -> void { cout << s << a << endl; } );

  Box ca;

  ca.callIt ();

  ca.setFun (f);

  ca.callIt ();

  ca.setFun ( [&] (string s) -> void { cout << s << a << endl; } );

  ca.callIt ();

  ca.setFun (fc);

  ca.callIt ();

} // ()

2
당신은 funValid 필요하지 않습니다 : en.cppreference.com/w/cpp/utility/functional/function/...를 , 단지 말if ( ! theFunction )
에릭 Aronesty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.