将std :: function()重定向到预C ++ 11中的自定义处理程序?

时间:2014-04-07 14:15:37

标签: c++ c++11 hook functor

我有这样的事情:

typedef std::function<void(int param1, int param2)> TheCallback;

void callTheCallback(TheCallback& theCallback) {
    theCallback(1, 2);
}

int main(int argc, char *argv[]) {
    TheCallback cb = [](int a, int b) { 
        std::cout << "Param 1:" << a << ", Param 2:" << b << std::endl;
    };

    cb(100, 200);
    return 0;
}

我的问题是 - 什么是钩住std :: function(或创建自定义&#34;向后兼容&#34; std :: function模板)的最佳方法,这样每次调用这样的函数时它都会在做其他事情之前还要打印一些自定义字符串(例如&#34; Called&#34;)?

nice solution for C++11 that uses variadic templates。那么C ++ 0x有什么类似的可能吗(例如Visual Studio 2010)?

3 个答案:

答案 0 :(得分:0)

我为这样处理它的回调创建一个包装器:

#include <iostream>     
#include <functional>

typedef std::function<void(int param1, int param2)> TheCallback;

class CallbackWrapper
{
public:
    CallbackWrapper(TheCallback callback)
        : m_callback(callback)
    {}

    void startCallback(int a, int b)
    {
        std::cout << "Called" << std::endl;
        m_callback(a, b);
    }

private:
    TheCallback m_callback;
};

int main(int argc, char* argv[])
{
    TheCallback cb = [](int a, int b) { 
        std::cout << "Param 1:" << a << ", Param 2:" << b << std::endl;
    };

    CallbackWrapper testCallback(cb);

    testCallback.startCallback(11, 22);

    return system("pause");
}

您甚至可以省略本地cb

int main(int argc, char* argv[])
{
    CallbackWrapper testCallback([](int a, int b) { 
        std::cout << "Param 1:" << a << ", Param 2:" << b << std::endl;
    });

    testCallback.startCallback(11, 22);

    return system("pause");
}

答案 1 :(得分:0)

在努力学习不同的选项之后,我找到了替代std :: function&lt;&gt;的解决方案。与兼容的模板。不完美,但这里目前适用于我:

template<class TFunc>
class hook_function : public std::function<TFunc>
{
public:
    typedef std::function<TFunc> FuncType;
    FuncType original;

    void hook()
    {
        std::cout << "Called." << std::endl;
    }

    hook_function() : FuncType()
    {}

    template<typename T>
    hook_function(T&& fn) 
        : original(std::forward<T>(fn)) 
        , FuncType(std::forward<T>(fn))
    {
    }

    hook_function(hook_function&& other) 
        : FuncType(static_cast<FuncType&&>(other))
    {
    }

    hook_function& operator=(hook_function&& other)
    {
        FuncType::operator=(static_cast<FuncType&&>(other));
        return *this;
    }

... insert more here ...

    void operator()(int a, int b)
    {
        hook();
        original(a, b);
    }

    void operator()(const std::string s)
    {
        hook();
        original(s);
    }
};

答案 2 :(得分:-1)

如果你想要一个通用的解决方案(不仅支持一个带两个整数的函数并返回void),那么你可以使用伪变量来支持一个函数,它可以将任意数量的参数提升到任意固定的限制(这个例子最多支持三个; VS2010的std::function最多可能需要10个。

void hook()
{
    std::cout << "Called\n";
}

template <typename R>
std::function<R()> wrap(std::function<R()> f)
{
    return [f]()->R { hook(); return f(); };
}

template <typename R, typename T0>
std::function<R(T0)> wrap(std::function<R(T0)> f)
{
    return [f](T0 v0)->R { hook(); return f(v0); };
}

template <typename R, typename T0, typename T1>
std::function<R(T0, T1)> wrap(std::function<R(T0, T1)> f)
{
    return [f](T0 v0, T1 v1)->R { hook(); return f(v0, v1); };
}

template <typename R, typename T0, typename T1, typename T2>
std::function<R(T0, T1, T2)> wrap(std::function<R(T0, T1, T2)> f)
{
    return [f](T0 v0, T1 v1, T2 v2)->R { hook(); return f(v0, v1, v2); };
}

template <typename F>
typename func_traits<F>::wrap_type wrap(F f)
{
    return wrap(typename func_traits<F>::wrap_type(f));
}

int main()
{
    auto cb = [](int a, int b){ std::cout << a << " " << b << "\n"; };
    auto wrap_cb = wrap(cb);
    wrap_cb(1, 2);
}

由于std::function的两层(每一层都需要virtual调用的成本),它并不是特别有效,但是对于大多数用途来说应该足够了,直到你可以升级到更好的编译器

编辑:感谢Martinho指出我的明显错误。上面的代码通过添加另一个wrap()重载来修复,该重载使用以下类型特征代码为推导的仿函数类型选择std::function的正确特化:

template <typename T>
struct func_traits;

template <typename R>
struct func_traits<R()>
{
    typedef std::function<R()> wrap_type;
};
template <typename R, typename A0>
struct func_traits<R(A0)>
{
    typedef std::function<R(A0)> wrap_type;
};
template <typename R, typename A0, typename A1>
struct func_traits<R(A0, A1)>
{
    typedef std::function<R(A0, A1)> wrap_type;
};
template <typename R, typename A0, typename A1, typename A2>
struct func_traits<R(A0, A1, A2)>
{
    typedef std::function<R(A0, A1, A2)> wrap_type;
};

template <typename R>
struct func_traits<R(*)()> : func_traits<R()> {};
template <typename R, typename A1>
struct func_traits<R(*)(A1)> : func_traits<R(A1)> {};
template <typename R, typename A1, typename A2>
struct func_traits<R(*)(A1, A2)> : func_traits<R(A1, A2)> {};
template <typename R, typename A1, typename A2, typename A3>
struct func_traits<R(*)(A1, A2, A3)> : func_traits<R(A1, A2, A3)> {};
template <typename R, typename C>
struct func_traits<R(C::*)()> : func_traits<R()> {};
template <typename R, typename A1, typename C>
struct func_traits<R(C::*)(A1)> : func_traits<R(A1)> {};
template <typename R, typename A1, typename A2, typename C>
struct func_traits<R(C::*)(A1, A2)> : func_traits<R(A1, A2)> {};
template <typename R, typename A1, typename A2, typename A3, typename C>
struct func_traits<R(C::*)(A1, A2, A3)> : func_traits<R(A1, A2, A3)> {};
template <typename R, typename C>
struct func_traits<R(C::*)() const> : func_traits<R()> {};
template <typename R, typename A1, typename C>
struct func_traits<R(C::*)(A1) const> : func_traits<R(A1)> {};
template <typename R, typename A1, typename A2, typename C>
struct func_traits<R(C::*)(A1, A2) const> : func_traits<R(A1, A2)> {};
template <typename R, typename A1, typename A2, typename A3, typename C>
struct func_traits<R(C::*)(A1, A2, A3) const> : func_traits<R(A1, A2, A3)> {};

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

template <typename T>
struct func_traits<T&> : func_traits<T> {};
template <typename T>
struct func_traits<T&&> : func_traits<T> {};

实例:http://coliru.stacked-crooked.com/a/1e5aeca5b01a36e6