16

考虑以下返回 lambda 的函数:

std::function<int()> make_counter()
{
    int i = 0;
    return [=]() mutable { return i++; };
}

是否可以返回实际的 lambda 类型,而不将其包装成std::function?

4

3 回答 3

20

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)。

于 2013-05-03T11:18:08.243 回答
10

如果您作弊并使用返回类型扣除,是的,您可以 (Link)

请注意,这只能在 C++11 本身之外实现,尽管它可以在常规的、非警告诱导的 C++11 中使用 lambda(即,返回该 lambda 的 lambda 内的 lambda)来完成。

于 2013-05-03T11:21:09.833 回答
0

是的,您可以使用受此博客文章启发的一些 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();
}
于 2019-03-20T03:04:50.240 回答