2

std::function「前」と「後」のフックで を飾る方法を見つけようとしています。

正しい構文を理解するのに苦労しています。これは私がこれまでに持っているものです:

// create a "before" hook
template<typename Functor, typename Hook>
Functor hook_before(const Functor & original, Hook hook)
{
    // not legal, but illustrates what I want to achieve
    template<typename Args ...args> 
    return [=](Args ...args)
    {
        hook();
        original(args...);
    };
}

私のサンプル アプリケーションはIdeoneにあります。

誰でも私がそれを理解するのを手伝ってくれますか?

4

3 に答える 3

3

次のようにできます。

#include <functional>
#include <iostream>

template <class Hook, class ReturnType, class... ArgType>
std::function<ReturnType(ArgType...)> hook_before(
    const std::function<ReturnType(ArgType...)>& original, 
    Hook hook)
{
    return [=](ArgType... args){
        hook();
        return original(std::move(args)...);
    };
}

int main()
{
    std::function<int(int, int)> sum = [](int a, int b) { return a + b; };

    std::cout << sum(3, 4) << std::endl;

    auto myhook = []() { std::cout << "Calculating sum" << std::endl; };
    auto hooked_sum = hook_before(sum, myhook);
    std::cout << hooked_sum(3, 4) << std::endl;
}

このhook_before関数は 2 つのファンクターを受け入れ、最初のファンクター (ArgType パラメーター パック) と同じ引数を受け入れる別のファンクターを返しますが、最初に呼び出しますhook

于 2012-06-06T09:53:49.950 に答える
3

ここに行きます(未テスト):

template <typename HOOK, typename RET, typename... ARGS>
struct BeforeHook {
    std::function<RET(ARGS...)> functor;
    HOOK hook;
    BeforeHook(blah) : blah {};

    RET operator()(ARGS&&... args) const {
        hook();
        return functor(args...);
    }
};

template <typename HOOK, typename RET, typename... ARGS>
BeforeHook<HOOK, RET, ARGS...> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
    return BeforeHook<HOOK, RET, ARGS...>(original, hook);
}

使用法:

auto hooked = hook_before(original_functor, hook_functor);
hooked(args_for_original_functor); // calls hook_functor, then original_functor

または、それらの線に沿った何か。original_functor は に変換可能である必要がありますがstd::function、呼び出し可能なものはほとんどすべてです。constどちらのファンクターもコスト呼び出し可能である必要がありますが、必要に応じてfromを削除できoperator()ます。

のインスタンスではなくラムダを返すことを試してみたい場合は、テンプレート引数とBeforeHookで同じトリックを使用し、ラムダでテンプレート引数パックを使用できるかどうかを確認してください。RET...ARGS

template <typename HOOK, typename RET, typename... ARGS>
std::function<RET(ARGS...)> hook_before(const std::function<RET(ARGS...)> &original, HOOK hook) {
    return [=](ARGS&&... args) -> RET {
        hook();
        return original(args...);
    };
}

std::functionいずれにせよ、重要なトリックは、テンプレートの引数推定で使用して、戻り値の型を引数から分離することだと思います。

于 2012-06-06T09:38:41.447 に答える
2

以下を試してください。

template<typename Functor, typename Hook>
struct BeforeHooked
{
    Functor f;
    Hook hook;

    template<class... Args>
    typename std::result_of<F(Args&&...)>::type
    operator()(Args&&... args)
    {
        hook();
        return f(std::forward<Args&&>(args)...);
    }
};

template<typename Functor, typename Hook>
Functor hook_before(Functor f, Hook hook)
{
    return BeforeHooked{f, hook};
}

コードはテストされていませんが、それをコンパイルできるコンパイラがあると仮定すると、あなたが望むことを行うべきだと思います。他の回答とは異なり、 だけstd::functionでなく、任意のファンクターを受け入れることができます。多形ファンクターを指定すると、多形のままになります。

于 2012-06-06T10:15:02.840 に答える