返回没有std :: function的lambda

时间:2013-05-03 11:16:22

标签: c++ c++11 lambda return-type higher-order-functions

考虑以下返回lambda的函数:

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

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

3 个答案:

答案 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();
}