如何在 C++11 中传递和执行匿名函数作为参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16111285/
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
How to pass and execute anonymous function as parameter in C++11?
提问by Mohsen Sarkar
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 { ... } );
回答by Yakk - Adam Nevraumont
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::functionuses type erasure to create a custom-created wrapper around your lambda, and then exposes a non-virtual interface that uses the pImplpattern to forward it to the custom-created wrapper.1
std::function使用类型擦除在 lambda 周围创建自定义创建的包装器,然后公开一个非虚拟接口,该接口使用该pImpl模式将其转发到自定义创建的包装器。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.
或者,用不太专业的术语来说,std::function<bool(int)>是一个类,它几乎可以包装您可以像函数一样调用的任何内容,传递一个与传递 an 兼容的参数int,并返回与返回 a 兼容的一些内容bool。
A call through a std::functionhas a run time cost roughly equal to a virtualfunction 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 调用std::function的运行时间成本大致等于virtual函数调用(由上述类型擦除引起),并且当您创建它时,它必须复制传入的函数对象(又名函子)的状态(这可能很便宜-- 无状态 lambdas,或通过引用捕获参数的 lambdas -- 或在其他一些情况下很昂贵)并存储它(通常在免费存储或堆上,这有成本),而纯模板版本可以“内联”在调用点(即,不仅可以比函数调用花费更少,编译器甚至可以优化函数调用和返回边界!)
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).
它使用一种称为“完美转发”的技术。对于某些函子,这会产生与 #1 略有不同的行为(通常是更正确的行为)。
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 constor non-constfunctor to be passed in.
大多数改进来自&&在参数列表中的使用:这意味着对函子的引用被传入(而不是副本),节省了一些成本,并允许传入const或非const函子。
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 thispointer. In theory, this could be useful, but the number of functors I've seen that actually override based on the rvalue status of thisis 0. When I'm writing serious library code (tm) I go to this bother, but rarely otherwise.
的std::forward<Lambda>(...)变化将仅导致行为上的变化,如果有人使用一种相对较新的C ++功能,允许方法(包括operator())覆盖上的右值/左值状态this指针。理论上,这可能很有用,但我见过的基于右值状态实际覆盖的函子数量this是0. 当我在编写严肃的库代码 (tm) 时,我会为此烦恼,但很少会这样做。
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 voidyou 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 falsewhen it wants to stop prematurely, and trueor voidotherwise.
还有一件可能的事情需要考虑。假设您想要获取返回bool的函数或返回的函数void,并且如果函数返回,void您希望将其视为返回true。例如,您正在使用一个在迭代某个集合时被调用的函数,并且您希望有选择地支持提前停止。该函数false在它想要过早停止时返回,true或void以其他方式返回。
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.
这是可能的,就我将要进入的范围而言(使用智能适配器或通过 SFINAE 技术)。但是,您最好只创建两个不同的命名函数,因为所需的技术太重了。
1Technically std::functioncould 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::functionimplementation I have interacted with.
1从技术上讲,std::function可以使用魔法仙尘来做它所做的事情,因为它的行为是由标准描述的,而不是它的实现。我正在描述一个简单的实现,它近似于std::function我与之交互的实现的行为。
回答by Andy Prowl
First solution:
第一个解决方案:
You can make your Func1()function a function template:
您可以使您的Func1()功能成为功能模板:
template<typename T>
bool Func1(int Arg1, T&& Arg2){
if(Arg1 > 0){
return Arg2(Arg1);
}
return false; // <== DO NOT FORGET A return STATEMENT IN A VALUE-RETURNING
// FUNCTION, OR YOU WILL GET UNDEFINED BEHAVIOR IF FLOWING
// OFF THE END OF THE FUNCTION WITHOUT RETURNING ANYTHING
}
You could then invoke it as you desire:
然后您可以根据需要调用它:
int main()
{
Func1(12, [](int D) -> bool { return D < 0; } );
}
Second solution:
第二种解决方案:
If you do not want to use templates, an alternative (that would bring some run-time overhead) is to use std::function:
如果您不想使用模板,另一种方法(会带来一些运行时开销)是使用std::function:
#include <functional>
bool Func1(int Arg1, std::function<bool(int)> Arg2){
if(Arg1 > 0){
return Arg2(Arg1);
}
return false;
}
Once again, this would allow you to call Func1()the way you desire:
再一次,这将允许您以您想要Func1()的方式调用:
int main()
{
Func1(12, [](int D) -> bool { return D < 0; } );
}
回答by Andy Ross
For those whose tastes are more traditional, note that non-capturing lambdas can convert to function pointers. So you can write your function above as:
对于那些口味更传统的人,请注意非捕获 lambda 可以转换为函数指针。因此,您可以将上面的函数编写为:
bool Func1(int Arg1, bool (*Arg2)(int)) { ... }
And it will work correctly for both traditional functions andlambdas.
并且它对于传统函数和lambda都可以正常工作。

