编写一个接受lambda表达式作为参数的函数

时间:2010-07-08 12:02:28

标签: c++ lambda c++11

我有这样的方法

template<typename T, typename U>
map<T,U> mapMapValues(map<T,U> old, T (f)(T,U))
{
    map<T,U> new;
    for(auto it = old.begin(); it != old.end(); ++it)
    {
        new[it->first] = f(it->first,it->second);
    }
    return new; 
}

并且想法是你这样称呼它

BOOST_AUTO_TEST_CASE(MapMapValues_basic)
{
    map<int,int> test;
    test[1] = 1;
    map<int,int> transformedMap = VlcFunctional::mapMapValues(test, 
        [&](int key, int value) -> int
        {
            return key + 1; 
        }
    );
}

但是我收到错误:没有函数模板实例“VlcFunctional :: mapMapValues”匹配参数列表参数类型是:(std :: map,std :: allocator&gt;&gt;,__ lambda1)

知道我做错了什么吗? Visual Studio 2008和Intel C ++编译器11.1

5 个答案:

答案 0 :(得分:37)

您的函数需要一个函数指针,而不是lambda。

在C ++中,通常有3种类型的“可调用对象”。

  1. 功能指针。
  2. 功能对象。
  3. Lambda函数。
  4. 如果您希望能够在功能界面中使用所有这些功能,那么您可以使用std::function

    template<typename T, typename U> 
    map<T,U> mapMapValues(map<T,U> old, std::function<T(T, U)> f)
    {
        ...
    }
    

    这将允许使用上述三种类型的可调用对象中的任何一种来调用该函数。但是,这种便利的代价是函数调用的少量开销(通常是空指针检查,然后通过函数指针调用)。这意味着该函数几乎肯定没有内联(除了可能使用高级WPO / LTO)。

    或者,您可以添加其他模板参数以为第二个参数采用任意类型。这样会更有效,但是你在使用的函数上失去了类型安全性,并且可能导致更多的代码膨胀。

    template<typename T, typename U, typename F> 
    map<T,U> mapMapValues(map<T,U> old, F f) 
    

答案 1 :(得分:12)

您的参数类型声明T (f)(T,U)的类型为'自由函数,其中包含TU并返回T'。除了具有该签名的实际函数之外,您不能将它传递给lambda,函数对象或其他任何东西。

您可以通过将参数类型更改为std::function<T(T,U)>来解决此问题:

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T,U)>)
{
}

或者,您可以将函数类型声明为模板参数,如下所示:

template<typename T, typename U, typename Fn> 
map<T,U> mapMapValues(map<T,U> old, Fn fn)
{
  fn(...);
}

答案 2 :(得分:10)

我想提供这个简单但不言自明的例子。它展示了如何传递&#34;可赎回的东西&#34; (函数,函数对象和lambda)到函数或对象。

// 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 ();

} // ()

答案 3 :(得分:5)

根据n3052,带有空捕获列表的Lambda表达式应该衰减为函数指针。但是,似乎这个功能没有在VC ++中实现,只有部分用g ++实现,请参阅我的SO question

答案 4 :(得分:1)

以下是如何将函数作为参数传递的一些示例

class YourClass
{
void YourClass::callback(void(*fptr)(int p1, int p2))
{
    if(fptr != NULL)
      fptr(p1, p2);
}
};

void dummyfunction(int p1, int p2)
{
   cout << "inside dummyfunction " << endl;
}

YourClass yc;

// using a dummyfunction as callback
yc.callback(&dummyfunction);

// using a lambda as callback
yc.callback( [&](int p1, int p2) { cout << "inside lambda callback function" << endl; } );

// using a static member function 
yc.callback( &aClass::memberfunction );