参数列表中带有省略号的C++ Lambda

Den*_*nis 6 c++ lambda variadic-functions generic-lambda c++14

我正在开发一个使用lambdas来描述表达式术语范围的库.因为库必须分发唯一的整数以标识每个变量,所以如果库(而不是用户)构造变量并且用户代码将它们作为lambda参数接收,则它是理想的.

(换句话说,我正在实现miniKanren的"call\fresh"的C++模拟.)

由于用户可能想要在特定范围内从零到多个新变量引入任何数字,我希望用户能够将具有不同数量参数的lambdas传递给库.但是,我不知道任何(简单的)方法(在C++ 14中)推导出任意lambda对象的参数数量.

我想到为什么不向lambda传递一个固定数量(比方说10)的variable-id参数,并让用户代码在lambda中使用省略号忽略不需要的那些?像这样的东西:

auto no_args = call_fresh([](...) { return success(); });
auto one_arg = call_fresh([](var A, ...) { return A == 1; });
auto two_args = call_fresh([](var A, var B, ...) { return A == 1 && B == 2; });
Run Code Online (Sandbox Code Playgroud)

编译器浏览器似乎接受lambda参数列表中的省略号,至少使用gcc.

它将被称为这样的东西(注意代码如何总是传递10个变量id,无论"f"是否只命名其中一个,两个或没有):

template <typename F>
auto call_fresh(F f)
{
   return [f](StateCounter sc) {
      return f(sc+0,sc+1,sc+2,sc+3,sc+4,
          sc+5,sc+6,sc+7,sc+8,sc+9);
   };
}
Run Code Online (Sandbox Code Playgroud)

虽然这是我感到惊讶的一个功能,有没有理由不使用带椭圆的lambdas?

max*_*x66 5

但是,我不知道有任何(简单的)方法(在 C++14 中)可以推断任意 lambda 对象的参数数量。

在我看来,您正在寻找sizeof...()一个可变参数auto列表

#include <iostream>

int main ()
 {
   auto l = [](auto ... as) { return sizeof...(as); };

   std::cout << l(1, 2L, 3.0, 4.0f, "5") << std::endl; // print 5
 }
Run Code Online (Sandbox Code Playgroud)


hlt*_*hlt 4

您的 lambda 本质上是 C 风格的可变参数函数。使用它们没有任何问题,如果您不想访问这些值(这有点难看),那也没关系。

然而,您似乎真正想要解决的根本问题是让您的库找到函数/lambda/...的参数数量(或arity),您可以使用模板元编程来完成此操作 - 无需您的用户来解决该问题。

披露:在我也在研究的一个库中有一个实现,这里

这是一个简单的例子:

template <typename Callable>
struct function_arity : public function_arity<decltype(&Callable::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_arity<ReturnType(ClassType::*)(Args...) const>
{
    constexpr static size_t arity = sizeof...(Args);
};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_arity<ReturnType(ClassType::*)(Args...)>
{
    constexpr static size_t arity = sizeof...(Args);
};
Run Code Online (Sandbox Code Playgroud)

编译器将自动为您推断出参数类型,并sizeof...为您提供所需的参数数量。

然后,您可以使用function_arity<decltype(lambda)>::arity来获取 lambda 的参数数量。最后一个版本涉及mutablelambda,其中调用运算符是非常量。您可能还想扩展它以使其正常工作noexcept,否则您将遇到类似libc++ bug 的错误。

不幸的是,这不适用于重载或模板化operator()(例如,如果您auto在 lambda 中使用 -type 参数)。如果您还想支持函数而不是 lambda,则可能需要额外的专业化。