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

Jam*_*ook 36 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; 
}
Run Code Online (Sandbox Code Playgroud)

而这个想法就是你这样称呼它

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; 
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

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

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

Pet*_*der 39

你的函数期望一个函数指针,而不是一个lambda.

在C++中,通常有3种类型的"可调用对象".

  1. 函数指针.
  2. 功能对象.
  3. Lambda函数.

如果您希望能够在功能界面中使用所有这些,那么您可以使用std::function:

template<typename T, typename U> 
map<T,U> mapMapValues(map<T,U> old, std::function<T(T, U)> f)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

template<typename T, typename U, typename F> 
map<T,U> mapMapValues(map<T,U> old, F f) 
Run Code Online (Sandbox Code Playgroud)

  • 你需要`#include <functional>`来使用`std :: function` (5认同)

Joe*_*oeG 12

您的参数类型声明T (f)(T,U)的类型为"自由函数取a T和a U并返回a 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)>)
{
}
Run Code Online (Sandbox Code Playgroud)

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

template<typename T, typename U, typename Fn> 
map<T,U> mapMapValues(map<T,U> old, Fn fn)
{
  fn(...);
}
Run Code Online (Sandbox Code Playgroud)


cib*_*en1 10

我想提供这个简单但不言自明的例子.它展示了如何将"可调用事物"(函数,函数对象和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 ();

} // ()
Run Code Online (Sandbox Code Playgroud)


raf*_*fak 5

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