定义函数时,lambda函数/表达式是什么类型的?

时间:2015-05-06 11:47:41

标签: c++ c++11 lambda

我想定义一个函数,它接受一个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; });

2 个答案:

答案 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的内容。 }。