我正在寻找的代码如下。
bool Func1(int Arg1, C++11LambdaFunc Arg2){
if(Arg1 > 0){
return Arg2(Arg1);
}
}
稍后我将使用此代码。
Func1(12, [](int D) -> bool { ... } );
答案 0 :(得分:44)
基本版本,用于头文件:
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
}
}
更复杂的版本,如果您想从实现中拆分接口(它有运行时成本):
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
使用类型擦除在lambda周围创建自定义创建的包装器,然后公开使用pImpl
模式的非虚拟接口将其转发到自定义创建的包装器。 SUP> 1
或者,在技术性较差的情况下,std::function<bool(int)>
是一个类,它可以包含几乎任何你可以调用的函数,传递一个与传递int
兼容的参数,并返回一些东西与返回bool
。
通过std::function
进行的调用的运行时间成本大致等于virtual
函数调用(由上述类型擦除引起),当您创建它时,它必须复制状态传入的函数对象(aka functor)(可以是廉价的 - 无状态lambdas,或通过引用捕获参数的lambda - 或者在其他一些情况下很昂贵)并存储它(通常在免费商店或堆上,这有成本)虽然纯模板版本可以在调用点“内联”(即,不仅可以比函数调用成本更低,编译器甚至可以优化函数调用并返回边界!)
第一个示例的精美版本,它也更好地处理了一些极端情况:(也必须在头文件中实现,或者在使用的翻译单元中实现)
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
}
}
使用称为“完美转发”的技术。对于某些仿函数,这会产生与#1略有不同的行为(通常更正确的行为)。
大部分改进来自于参数列表中&&
的使用:这意味着传入对仿函数的引用(而不是副本),从而节省了一些成本,并允许const
传递1}}或非 - const
仿函数。
std::forward<Lambda>(...)
更改只会导致行为更改,如果有人使用相对较新的C ++功能,允许方法(包括operator()
)覆盖{{1}的rvalue / lvalue状态指针。从理论上讲,这可能很有用,但我看到的基于this
的右值状态实际覆盖的仿函数是this
。当我写严肃的图书馆代码(tm)时,我会去打扰这个,但很少这样做。
还有一件事可以考虑。假设你想要一个返回0
的函数,或者一个返回bool
的函数,如果函数返回void
,你想要把它当作它返回{{1} }。例如,在迭代某个集合时,您正在调用正在调用的函数,并且您希望选择性地支持早期暂停。该函数在想要提前停止时返回void
,否则返回true
或false
。
或者,在更一般的情况下,如果你有一个函数的多个覆盖,其中一个取一个函数而另一个取一些其他类型在同一个位置。
这是可能的,这是我将要进入这里(使用智能适配器,或通过SFINAE技术)。但是,你可能最好只创建两个不同的命名函数,因为所需的技术太重了。
1 从技术上讲,true
可以使用神奇的尘埃来做它所做的事情,因为它的行为是由标准描述的,而不是它的实现。我正在描述一个简单的实现,它近似于我与之交互的void
实现的行为。
答案 1 :(得分:18)
第一个解决方案:
您可以将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
}
然后您可以根据需要调用它:
int main()
{
Func1(12, [](int D) -> bool { return D < 0; } );
}
第二个解决方案:
如果您不想使用模板,另一种选择(会带来一些运行时开销)是使用std::function
:
#include <functional>
bool Func1(int Arg1, std::function<bool(int)> Arg2){
if(Arg1 > 0){
return Arg2(Arg1);
}
return false;
}
再次,这将允许您按照您希望的方式拨打Func1()
:
int main()
{
Func1(12, [](int D) -> bool { return D < 0; } );
}
答案 2 :(得分:11)
对于那些口味更传统的人,请注意非捕获lambdas可以转换为函数指针。所以你可以把上面的函数编写为:
bool Func1(int Arg1, bool (*Arg2)(int)) { ... }
它将适用于传统函数和 lambdas。