3

最後のパラメーターをバインドしながら、std ::function<>オブジェクトを変換する簡単な関数を作成しようとしています。それは私が持っているものです:

template<typename R, typename Bind, typename ...Args> std::function<R (Args...)> bindParameter (std::function<R (Args..., Bind)> f, Bind b)
{
    return [f, b] (Args... args) -> R { return f (args..., b); };
}

そして、それが私がそれを使いたい方法です:

int blub (int a, int b)
{
    return a * b;
}

// ...

int main ()
{
    std::function<int (int, int)> f1 (blub);

    // doesn't work
    std::function<int (int)> f2 = bindParameter (f1, 21);

    // works
    std::function<int (int)> f3 = bindParameter<int, int, int> (f1, 21);

    return f2 (2);
}

...この例では、main関数は42を返す必要があります。問題は、gcc(4.6)がテンプレートパラメータのタイプを正しく推測していないように見えるため、最初のバージョンでは次のエラーが発生します。

test.cpp:35:58: error: no matching function for call to 'bindParameter(std::function<int(int, int)>&, int)'
test.cpp:35:58: note: candidate is:
test.cpp:21:82: note: template<class R, class Bind, class ... Args> std::function<R(Args ...)> bindParameter(std::function<R(Args ..., Bind)>, Bind)

しかし、私の意見では、パラメータは明らかです。または、この種の型推論は標準でカバーされていないか、gccでまだ実装されていませんか?

4

2 に答える 2

3

std::function関数テンプレートの推定パラメーターとして使用することはできません。int(*)(int, int)一致するルールがないため、この方法では演繹は機能しませんstd::function<int(int, int)>。(ほとんどの場合、これがインスタンス化されたときにエラーになる場合でも、any std::function<Signature>には を受け入れるコンストラクターがあることも考慮してください。)int(*)(int, int)

一般的なケースで functor のシグネチャを検出するのは問題があります。KennyTM のソリューションでさえも制限があります: モノモーフィック ファンクターと関数のようなもののシグネチャを検出しますが、ポリモーフィック ファンクター (オーバーロードされoperator()た など) やサロゲート コール関数を持つファンクター (モノモーフィックの場合でも) では機能しません。

decltypeただし、 (または同等の)のおかげで署名を検出する問題を完全に回避することは可能でstd::result_ofあり、そうすることをお勧めします。したがって、KennyTM の回答の変形:

template<typename Functor, typename Bound>
struct bind_last_type {
    Functor functor;
    Bound bound;

    template<typename... Args>
    auto operator()(Args&&... args)
    -> typename std::result_of<Functor&(Args..., Bound)>::type
    // equivalent:
    // -> decltype( functor(std::forward<Args>(args)..., std::move(bound)) )
    { return functor(std::forward<Args>(args)..., std::move(bound)); }
};

template<typename Functor, typename Bound>
bind_last_type<
    typename std::decay<Functor>::type
    , typename std::decay<Bound>::type
>
bind_last(Functor&& functor, Bound&& bound)
{ return { std::forward<Functor>(functor), std::forward<Bound>(bound) }; }
于 2011-11-18T07:57:33.497 に答える
1

推論についてはわかりませんが、テンプレート化された関数オブジェクトを定義するだけで機能します。

template <typename FType, typename LastArgType>
struct BindLastHelper
{
    FType _f;
    LastArgType _last_arg;

    template <typename... Args>
    typename utils::function_traits<FType>::result_type
        operator()(Args&&... args) const
    {
        return _f(std::forward<Args>(args)..., _last_arg);
    }
};

template<typename FType, typename LastArgType>
BindLastHelper<FType, LastArgType> bindParameter (FType f, LastArgType b)
{
    return BindLastHelper<FType, LastArgType>{f, b};
}

ノート:

于 2011-11-17T18:05:51.130 に答える