考虑以下返回 lambda 的函数:
std::function<int()> make_counter()
{
int i = 0;
return [=]() mutable { return i++; };
}
是否可以返回实际的 lambda 类型,而不将其包装成std::function
?
考虑以下返回 lambda 的函数:
std::function<int()> make_counter()
{
int i = 0;
return [=]() mutable { return i++; };
}
是否可以返回实际的 lambda 类型,而不将其包装成std::function
?
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)。
如果您作弊并使用返回类型扣除,是的,您可以 (Link)。
请注意,这只能在 C++11 本身之外实现,尽管它可以在常规的、非警告诱导的 C++11 中使用 lambda(即,返回该 lambda 的 lambda 内的 lambda)来完成。
是的,您可以使用受此博客文章启发的一些 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 {};
}
现在您可以声明一个“私有”函数,该函数利用 lambda确实具有返回类型推导这一事实:
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();
}