6

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)
    {}
};

渡された関数の引数と戻り値の型を指定する必要がないように、いくつかの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 };
}

ただし、make_fooラムダをパラメーターとして受け取るオーバーロードを作成できませんでした。

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

戻り値の型と引数の型をラムダから自動的に推定する方法が見つかりません。このような問題を解決する慣用的な方法はありますか?

4

2 に答える 2

4

よし、死ぬかと思ったけど、やっと行けた ç_ç

まず、通常のインデックスを使用しました。私は公式のものを持っていないので、数ヶ月前に書いた古いインデックスを使用しました:

template<std::size_t...>
struct indices {};

template<std::size_t N, std::size_t... Ind>
struct make_indices:
    make_indices<N-1, N-1, Ind...>
{};

template<std::size_t... Ind>
struct make_indices<0, Ind...>:
    indices<Ind...>
{};

次に、StackOverflow のどこかにある関数特性をいくつか使用しました。それらは素晴らしく、コメントでリンクされている Boost ライブラリと同等だと思います。

template<typename T>
struct function_traits:
    function_traits<decltype(&T::operator())>
{};

template<typename C, typename Ret, typename... Args>
struct function_traits<Ret(C::*)(Args...) const>
{
    enum { arity = sizeof...(Args) };

    using result_type = Ret;

    template<std::size_t N>
    using arg = typename std::tuple_element<N, std::tuple<Args...>>::type;
};

次に、make_foo両方ともインデックスを使用する必要があるため、適切な関数とその実装関数を作成できました。注意してください、それは明らかに醜いです:

template<typename Function, std::size_t... Ind>
auto make_foo_(Function&& func, indices<Ind...>)
    -> Foo<
        typename function_traits<typename std::remove_reference<Function>::type>::result_type,
        typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...>
{
    using Ret = typename function_traits<typename std::remove_reference<Function>::type>::result_type;
    return { std::function<Ret(typename function_traits<typename std::remove_reference<Function>::type>::template arg<Ind>...)>(func) };
}

template<typename Function, typename Indices=make_indices<function_traits<typename std::remove_reference<Function>::type>::arity>>
auto make_foo(Function&& func)
    -> decltype(make_foo_(std::forward<Function>(func), Indices()))
{
    return make_foo_(std::forward<Function>(func), Indices());
}

コードはどこか醜くて読めませんが、間違いなく機能します。現在、実装定義の動作に依存していないことを願っています。また、みなさんのアドバイスも参考になりました!:)

int main()
{
    auto lambda = [](int i, float b, long c)
    {
        return long(i*10+b+c);
    };

    auto foo = make_foo(lambda);
    std::cout << foo(5, 5.0, 2) << std::endl; // 57, it works!
}

そして、これがライブの例です:)

于 2013-11-12T16:06:40.187 に答える