我想定义一个函数,它接受一个lambda函数(除了通常的输入参数)。我想尽可能地限制该函数(它自己的输入和返回类型)。
int myfunc( const int a, LAMBDA_TYPE (int, int) -> int mylamda )
{
return mylambda( a, a ) * 2;
}
这样我可以按如下方式调用函数:
int input = 5;
myfunc( input, [](int a, int b) { return a*b; } );
定义myfunc
的正确方法是什么?
有没有办法定义默认的lambda?像这样:
int myfunc( const int a, LAMBDA_TYPE = [](int a, int b) { return a*b; });
答案 0 :(得分:7)
如果你选择std::function<int(int,int)>
它会有开销,但它会做你想要的。它甚至可以在C ++ 14中正确过载。
如果您不想要std::function
的类型擦除和分配开销,您可以这样做:
template<
class F,
class R=std::result_of_t<F&(int,int)>,
class=std::enable_if_t<std::is_same<int,R>{}>
>
int myfunc( const int a, F&& f )
或检查可兑换性为int
而不是同一性。这是sfinae解决方案。 1
这将正确过载。为简洁起见,我使用了一些C ++ 14功能。在C ++ 11中将blah_t<?>
替换为typename blah<?>::type
。
另一种选择是static_assert
类似的条款。这会生成最佳错误消息。
最后你可以使用它:如果它不能像你使用它那样使用,代码将无法编译。
在C ++ 1z概念中,将有更简单/更少的代码沙拉方式来实现sfinae解决方案。
1 在一些编译器上std::result_of
无法与sfinae玩得很好。在那些上,用decltype(std::declval<F&>()(1,1))
替换它。除非您的编译器不支持C ++ 11(如msvc 2013和2015),否则这将起作用。 (幸运的是2013/3015有一个不错的result_of
)。
答案 1 :(得分:1)
有两种选择,类型擦除std::function<signature>
强制一个特定的签名,与你的问题一致,但它会增加一些额外的成本(主要是它不能一般地内联)。另一种方法是使用模板,将最后一个参数作为通用对象。从性能的角度来看,这种方法可能会更好,但是您要将语法检查留给编译器(我不认为这是一个问题)。其中一条评论提到将lambda作为函数指针传递,但这只适用于没有捕获的lambda。
我个人会选择第二种选择:
template <typename Fn>
int myFunc(const int a, Fn&& f) {
return f(a, a) * 2;
}
请注意,虽然这不会明确强制使用特定签名,但编译器会强制f
可以使用两个int
进行调用,并产生可以乘以2并转换为int
的内容。 }。