假设我有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; }
。
答案 0 :(得分:3)
std::function<int(int a, int b, int c)>
中的变量名称不属于该类型 - 它们基本上是注释。没有办法在任何其他方面提取它们。
因此,如果您希望获得a
,b
和c
,那么您将失去运气。
您可以做的一件事就是使用auto
:
foo( [](auto...args) { return args+...+0; } );
接近你想要的。如果你有3个参数,你可以这样做:
foo( [](auto a, auto b, auto c) { return a+b+c; } );
但返回类型不匹配,只是因为std::function
为您进行转换。
您可以提取a
b
和c
的类型,并使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可以存储,复制和调用任何Callable目标 - 函数, lambda表达式,绑定表达式或其他函数 对象,以及指向成员函数和指向数据的指针 成员。
- 来源cppreference.com
所以是的,这种方法完全有效!
然而,typedef的签名不能用于短路lambda定义。
备注: typedef是关于返回类型和参数类型而不是参数名称,所以如果短路参数列表是合法的,lambda的主体就不知道哪个要使用的参数:
int main() {
foo([](int d, int e, int f){ return d + e + f; });
}