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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3203305/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:19:11  来源:igfitidea点击:

Write a function that accepts a lambda expression as argument

c++lambdac++11

提问by Jamie Cook

I have a method like this

我有这样的方法

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; 
}

and the idea is that you'd call it like this

这个想法是你会这样称呼它

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; 
        }
    );
}

However I get the error: no instance of function template "VlcFunctional::mapMapValues" matches the argument list argument types are: (std::map, std::allocator>>, __lambda1)

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

Any idea what I'm doing wrong? Visual Studio 2008 and Intel C++ compiler 11.1

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

回答by Peter Alexander

Your function is expecting a function pointer, not a lambda.

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

In C++, there are, in general, 3 types of "callable objects".

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

  1. Function pointers.
  2. Function objects.
  3. Lambda functions.
  1. 函数指针。
  2. 函数对象。
  3. Lambda 函数。

If you want to be able to use all of these in your function interface, then you could use std::function:

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

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

This will allow the function to be called using any of the three types of callable objects above. However, the price for this convenience is a small amount of overhead on invokations on the function (usually a null pointer check, then a call through a function pointer). This means that the function is almost certainly not inlined (except maybe with advanced WPO/LTO).

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

Alternatively, you could add an additional template parameter to take an arbitrary type for the second parameter. This will be more efficient, but you lose type-safety on the function used, and could lead to more code bloat.

或者,您可以添加一个额外的模板参数来为第二个参数采用任意类型。这将更有效,但您会失去所使用函数的类型安全性,并可能导致更多的代码膨胀。

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

回答by JoeG

Your parameter type declaration T (f)(T,U)is of type 'free function taking a Tand a Uand returning a T'. You can't pass it a lambda, a function object, or anything except an actual function with that signature.

您的参数类型声明T (f)(T,U)属于“自由函数采用 aT和 aU并返回 a T”的类型。除了具有该签名的实际函数之外,您不能将 lambda、函数对象或任何东西传递给它。

You could solve this by changing the type of the parameter to std::function<T(T,U)>like this:

你可以通过改变参数的类型来解决这个std::function<T(T,U)>问题:

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

Alternately, you could declare the function type as a template argument like this:

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

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

回答by cibercitizen1

I would like to contribute this simple but self-explanatory example. It shows how to pass "callable things" (functions, function objects, and lambdas) to a function or to an object.

我想贡献这个简单但不言自明的例子。它展示了如何将“可调用的东西”(函数、函数对象和 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 ();

} // ()

回答by rafak

Lambda expressions with empty capture list should decay to function pointers, according to n3052. However it seems that this feature is not implemented in VC++ and only partially in g++, see my SO question.

根据n3052,具有空捕获列表的 Lambda 表达式应该衰减为函数指针。但是,似乎此功能未在 VC++ 中实现,仅部分在 g++ 中实现,请参阅我的 SO问题

回答by serup

Here is some example of how to pass a function as parameter

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

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