考虑以下返回lambda的函数:
std::function<int()> make_counter()
{
int i = 0;
return [=]() mutable { return i++; };
}
是否可以返回实际的lambda类型,而不将其包装到std::function
?
答案 0 :(得分:19)
C ++ 11:不。我引用每个lambda表达式(§5.1.2/ 3):
[...] 唯一,未命名的非联合类类型[...]
这实际上意味着在不首先知道相应表达式的情况下就无法知道lambda的类型。
现在,如果你没有捕获任何东西,你可以使用转换到函数指针并返回它(函数指针类型),但这是非常有限的。
正如@Luc在休息室中所说,如果您愿意更换make_counter
(如果它不是模板,或超载或其他东西),以下内容将起作用:
auto const make_counter = [](int i = 0) {
return [i]() mutable { return i++; };
};
C ++ 1y:是的,通过对正常函数的返回类型推导(N3582)。
答案 1 :(得分:10)
如果你作弊并使用退货类型扣除,yes you can (Link)。
注意这只能在C ++ 11本身之外实现,尽管它可以在使用lambdas的常规,非警告诱导C ++ 11中完成(也就是说,lambda中的lambda返回lamba)。
答案 2 :(得分:0)
是的,您可以通过受this blog post启发的一些lambda技巧来做到这一点。
第一步是提供一个帮助程序,以使lambda成为文字类型:
template<class F>
struct literal_lambda_t {
static_assert(std::is_empty<F>(), "Lambdas must be empty (have no captures)");
template<typename... Args>
auto operator()(Args&&... args) const -> decltype(
std::declval<F const&>()(std::forward<Args>(args)...)
) {
// since the object is empty, reinterpreting it should be safe
return reinterpret_cast<const F&>(*this)(std::forward<Args>(args)...);
}
};
template<class F>
constexpr literal_lambda_t<typename std::remove_reference<F>::type> literal_lambda(F &&f) {
return {};
}
现在,您可以声明一个“私有”函数,该函数利用lambdas do 具有返回类型推断的事实:
namespace detail {
static constexpr auto make_counter = literal_lambda([](){
int i = 0;
return [=]() mutable { return i++; };
});
}
最后,您可以根据此私有lambda声明实际函数:
auto make_counter() -> decltype(detail::make_counter()) {
return detail::make_counter();
}
这种方法甚至适用于模板化函数:
namespace detail {
template<typename T>
struct typed_counter_helper {
// can't template this, so have to template an enclosing struct
static constexpr auto f = literal_lambda([](){
T i = 0;
return [=]() mutable { return i++; };
});
};
}
template<typename T>
auto make_typed_counter() -> decltype(typed_counter_helper<T>::f()) {
return typed_counter_helper<T>::f::make_counter();
}