如何传递和执行匿名函数作为参数在C ++ 11? [英] How to pass and execute anonymous function as parameter in C++11?

查看:2760
本文介绍了如何传递和执行匿名函数作为参数在C ++ 11?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找的代码如下。

  bool Func1(int Arg1,C ++ 11LambdaFunc Arg2) {
if(Arg1> 0){
return Arg2(Arg1);
}
}

稍后我将使用此代码。 p>

  Func1(12,[](int D) - > bool {...}); 


解决方案

基本版本,用于头文件: / p>

  template< typename Lambda> 
bool Func1(int Arg1,Lambda Arg2){//或Lambda&&&&通常更好
if(Arg1> 0){
return Arg2(Arg1);
} else {
return false; //记住,所有控制路径都必须返回值
}
}

更复杂的版本,如果你想从你的实现中分离你的接口(它有运行时的成本):

  bool Func1 Arg1,std :: function< bool(int)> Arg2){
if(Arg1> 0){
return Arg2(Arg1);
} else {
return false; //记住,所有控制路径都必须返回值
}
}

std :: function 使用类型擦除在您的lambda周围创建一个自定义创建的包装,然后公开一个非虚拟接口,使用 pImpl 模式将其转发到自定义创建的包装器。 1

或者, $ c> std :: function< bool(int)> 是一个类,可以包装几乎任何你可以调用像一个函数,传递一个参数,与传递 int ,并返回与返回 bool 兼容的内容。



通过 std :: function 调用的调用具有大致等于 virtual 函数调用的运行时成本上面的类型擦除),当你创建它时,它必须复制函数对象(aka函子)传入的状态(可以是廉价的 - 无状态lambdas,或lambdas捕获参数引用 - 或昂贵的其他情况)并存储它(通常在免费存储或堆上,其具有成本),而纯模板版本可以在调用点处内联(即,不仅成本小于函数调用,编译器甚至可以优化函数调用和返回边界!)



第一个例子的一个花哨的版本,也处理一些角落的情况更好:(也必须实现在头文件中,或在与所使用的相同的翻译单元中)

  template< typename Lambda> 
bool Func1(int Arg1,Lambda&& Arg2){
if(Arg1> 0){
return std :: forward L(Arg2)(Arg1)
} else {
return false; //记住,所有控制路径都必须返回值
}
}

其使用被称为完美转发的技术。对于一些函子,这会产生与#1略有不同的行为(通常更正确的行为)。



大多数改进来自于使用 &&&&&&&&&&&< / code>:这意味着对函子的引用被传递(而不是拷贝),节省一些代价,并允许 / code>或非 - const 函数。



std :: forward< Lambda>(...)改变将仅导致行为的改变,如果某人使用相对较新的C ++特征来允许方法(包括 )覆盖指针的rvalue / lvalue状态。理论上,这可能是有用的,但是我看到的函数的数量实际上基于 的右值状态覆盖 0 。当我编写严格的库代码(tm)时,我会去这个麻烦,但很少其他。



还有一个可能的事情要考虑。假设你想要一个返回 bool 的函数,或者返回 void 的函数,如果函数返回 void 您希望将其视为返回 true 。例如,当你迭代一些集合时,你正在调用一个被调用的函数,并且你可以选择支持早期暂停。当它想要提前停止时,该函数返回 false ,并且 true void 否则。



或者,在更一般的情况下,如果你有一个函数的多个重写,其中一个接受一个函数,在同一位置。



这是可能的,这是我要进入这里(使用智能适配器,或通过SFINAE技术)。但是,你最好只是创建两个不同的命名函数,因为所需的技术太重了。






1 技术上 std :: function 可以使用魔法尘埃做它做的,因为它的行为是标准描述的,而不是它的实现。我描述一个简单的实现,近似与我已经交互的 std :: function 实现的行为。


The code I'm looking for is like following.

bool Func1(int Arg1, C++11LambdaFunc Arg2){
    if(Arg1 > 0){
        return Arg2(Arg1);
    }
}

Later I'll be using this code.

Func1(12, [](int D) -> bool { ... } );

解决方案

Basic version, for use in a header file:

template<typename Lambda>
bool Func1(int Arg1, Lambda Arg2){ // or Lambda&&, which is usually better
  if(Arg1 > 0){
    return Arg2(Arg1);
  } else {
    return false; // remember, all control paths must return a value
  }
}

More complex version, if you want to split your interface from your implementation (it has run time costs):

bool Func1(int Arg1, std::function<bool(int)> Arg2){
  if(Arg1 > 0){
    return Arg2(Arg1);
  } else {
    return false; // remember, all control paths must return a value
  }
}

std::function uses type erasure to create a custom-created wrapper around your lambda, and then exposes a non-virtual interface that uses the pImpl pattern to forward it to the custom-created wrapper.1

Or, in less technical terms, std::function<bool(int)> is a class that can wrap nearly anything that you can call like a function, passing one parameter that is compatible with passing an int, and it returns something that is compatible with returning a bool.

A call through a std::function has a run time cost roughly equal to a virtual function call (caused by the above type erasure), and when you create it it has to copy the state of the function object (aka functor) passed in (which can be cheap -- stateless lambdas, or lambdas capturing arguments by reference -- or expensive in some other cases) and store it (typically on the free store or heap, which has a cost), while the pure-template versions can be "inlined" at the point of call (ie, can not only cost less than a function call, the compiler can even optimize over the function call and return boundaries!)

A fancy version of the first example that also handles some corner cases a tad better: (also must be implemented within a header file, or in the same translation unit as it is used)

template<typename Lambda>
bool Func1(int Arg1, Lambda&& Arg2){
  if(Arg1 > 0){
    return std::forward<Lambda>(Arg2)(Arg1);
  } else {
    return false; // remember, all control paths must return a value
  }
}

which uses a technique known as "perfect forwarding". For some functors, this generates slightly different behavior than #1 (and usually more correct behavior).

Most of the improvement comes form the use of && in the argument list: this means that a reference to the functor is passed in (instead of a copy), saving some costs, and allows both a const or non-const functor to be passed in.

The std::forward<Lambda>(...) change would only cause a change in behavior if someone used a relatively new C++ feature that allows methods (including operator()) to override on the rvalue/lvalue status of the this pointer. In theory, this could be useful, but the number of functors I've seen that actually override based on the rvalue status of this is 0. When I'm writing serious library code (tm) I go to this bother, but rarely otherwise.

There is one more possible thing to consider. Suppose you want to take either a function that returns bool, or a function that returns void, and if the function returns void you want to treat it as if it returned true. As an example, you are taking a function that is being called when iterating over some collection, and you want to optionally support early halting. The function returns false when it wants to stop prematurely, and true or void otherwise.

Or, in a more general case, if you have multiple overrides of a function, one of which takes a function and others take some other type at the same location.

This is possible, which is as far as I'm going to get into here (either with a smart adapter, or via SFINAE techniques). However, you are probably better off just creating two different named functions, because the techniques required are way too heavy weight.


1 Technically std::function could use magic fairy dust to do what it does, as its behavior is described by the standard, and not its implementation. I'm describing a simple implementation that approximates the behavior of the std::function implementation I have interacted with.

这篇关于如何传递和执行匿名函数作为参数在C ++ 11?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆