可以使用std :: function typedef来帮助定义lambda吗?

时间:2018-01-07 23:02:26

标签: c++ c++11 lambda

假设我有typedef特定std::function,例如:

typedef std::function<int(int a, int b, int c)> func_type;

在定义实现它的lambda时,我可以重用那个typedef吗?

例如,在下面的示例中,函数foo接受func_type,但foo的调用网站需要复制签名:

void foo(func_type f) {
  // ...
}

int main() {
  foo([](int a, int b, int c){ return a + b + c; });
}

我可以在声明lambda时以某种方式重用func_type typedef,所以我不必重复参数列表(因此func_type typedef的更改对于lambda体是透明的适用于新定义。)

类似于[](??? func_type ???){ return a + b + c; }

3 个答案:

答案 0 :(得分:3)

std::function<int(int a, int b, int c)>中的变量名称不属于该类型 - 它们基本上是注释。没有办法在任何其他方面提取它们。

因此,如果您希望获得abc,那么您将失去运气。

您可以做的一件事就是使用auto

foo( [](auto...args) { return args+...+0; } );

接近你想要的。如果你有3个参数,你可以这样做:

foo( [](auto a, auto b, auto c) { return a+b+c; } );

但返回类型不匹配,只是因为std::function为您进行转换。

您可以提取a bc的类型,并使lambda的工作方式不同,但不能使用返回类型。除非你做一些疯狂的事情:

template<class T>
struct tag_t{ contexpr tag_t(){} using type=T; };
template<class T>
constexprt tag_t<T> tag{};
template<class Tag>
using type_t = typename Tag::type;

template<class F>
struct deducer {
  F f;
  template<class R, class...Args>
  operator std::function<R(Args...)>() const {
    return f( tag<R>, tag<Args>... );
  }
};

template<class F>
deducer<F> make_deducer( F f ){ return {std::move(f)}; }

int main() {
  foo(make_deducer([](auto R, auto...Args){
    return []( type_t<decltype(Args)>... args )->type_t<decltype(R)> {
      return 0+...args;
    });
  }));
}

我会反对这一点。但是我从传递给std::function的{​​{1}}推导出了lambda的参数类型和返回类型。

我们在这里做的是创建一个演绎者类型,当转换为std::function时,将参数和返回类型传递给它存储的lambda。然后,lambda为那些确切的参数生成自定义lambda。

这既不简短,也不简单。

答案 1 :(得分:1)

如果你知道你有一个std::function而你想要做的是将类型参数的选择推迟到std::function,你就可以拥有一个通用的lambda:

foo([](auto... xs) { return (... + xs); });

由于它的std::function调用运算符驱动lambda的调用方式,所以这样做是正确的。当然,这需要C ++ 14(我上面使用的fold-expression需要C ++ 17,但这并不重要)。您可能会或可能不想使用auto&&,具体取决于实际类型。

对于C ++ 11,你不能轻易地用lambda做这样的事情。您需要修复arity并手动列出所有类型。这不实用。你可以回退到使用普通的函数对象,使用调用操作符模板,但是你失去了lambda的优点。

答案 2 :(得分:0)

std::function

  

是一个通用的多态函数包装器。实例   std :: function可以存储,复制和调用任何Callable目标 -   函数, lambda表达式,绑定表达式或其他函数   对象,以及指向成员函数和指向数据的指针   成员。
- 来源cppreference.com

所以是的,这种方法完全有效!

然而,typedef的签名不能用于短路lambda定义。

备注: typedef是关于返回类型和参数类型而不是参数名称,所以如果短路参数列表是合法的,lambda的主体就不知道哪个要使用的参数:

int main() {
  foo([](int d, int e, int f){ return d + e + f; });
}