初始化包含带有lambda的std :: function的类

Mor*_*enn 5 c++ lambda templates c++11 std-function

我创建了一个模板类,其中包含std::function一个成员,方法如下:

template<typename Ret, typename... Args>
class Foo
{
private:
    std::function<Ret(Args...)> _func;

public:
    Foo(const std::function<Ret(Args...)>& func):
        _func(func)
    {}
};
Run Code Online (Sandbox Code Playgroud)

为了不必指定传递函数的参数和返回类型,我创建了一些make_foo重载:

template<typename Ret, typename... Args>
auto make_foo(Ret (&func)(Args...))
    -> Foo<Ret, Args...>
{
    return { std::function<Ret(Args...)>(func) };
}

template<typename Ret, typename... Args>
auto make_foo(const std::function<Ret(Args...)>& func)
    -> Foo<Ret, Args...>
{
    return { func };
}
Run Code Online (Sandbox Code Playgroud)

但是,我无法创建一个make_foo以lambda作为参数的重载:

template<typename Ret, typename... Args>
auto make_foo(??? func)
    -> Foo<Ret, Args...>
{
    return { std::function<Ret(Args...)>(func) };
}
Run Code Online (Sandbox Code Playgroud)

我只是找不到从lambda自动推导出返回类型和参数类型的方法.有没有一种解决这种问题的惯用方法?

Mor*_*enn 4

好吧,所以我以为我会死,但我终于做到了 \xc3\xa7_\xc3\xa7

\n\n

首先,我使用了常用的索引。由于我没有官方的索引,因此我使用了几个月前编写的旧索引:

\n\n
template<std::size_t...>\nstruct indices {};\n\ntemplate<std::size_t N, std::size_t... Ind>\nstruct make_indices:\n    make_indices<N-1, N-1, Ind...>\n{};\n\ntemplate<std::size_t... Ind>\nstruct make_indices<0, Ind...>:\n    indices<Ind...>\n{};\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,我使用了在 StackOverflow 上找到的一些函数特征。它们很好,我认为它们相当于评论中链接的 Boost 库:

\n\n
template<typename T>\nstruct function_traits:\n    function_traits<decltype(&T::operator())>\n{};\n\ntemplate<typename C, typename Ret, typename... Args>\nstruct function_traits<Ret(C::*)(Args...) const>\n{\n    enum { arity = sizeof...(Args) };\n\n    using result_type = Ret;\n\n    template<std::size_t N>\n    using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,我能够编写一个适当的make_foo函数及其实现函数,因为两者都需要使用索引。小心点,它很丑陋:

\n\n
template<typename Function, std::size_t... Ind>\nauto make_foo_(Function&& func, indices<Ind...>)\n    -> Foo<\n        typename function_traits<typename std::remove_reference<Function>::type>::result_type,\n        typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>\n{\n    using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;\n    return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };\n}\n\ntemplate<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>\nauto make_foo(Function&& func)\n    -> decltype(make_foo_(std::forward<Function>(func), Indices()))\n{\n    return make_foo_(std::forward<Function>(func), Indices());\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

该代码有些丑陋且不可读,但它确实有效。希望它现在不依赖于某些实现定义的行为。另外,谢谢大家的建议,很有帮助!:)

\n\n
int main()\n{\n    auto lambda = [](int i, float b, long c)\n    {\n        return long(i*10+b+c);\n    };\n\n    auto foo = make_foo(lambda);\n    std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

这是一个活生生的例子:)

\n