C++函数装饰器

Gen*_*ure 7 c++ templates c++11

我正在寻找一种在C++中装饰函数或lambdas的方法.目标是在函数调用之前和之后执行某些操作.正如我所见,最接近使用的是std :: function,但它需要具有其参数的类型.

class FunctionDecorator
{
public:
    FunctionDecorator( std::function func )
        : m_func( func )

    void operator()()
    {
        // do some stuff prior to function call

        m_func();

        // do stuff after function call
    }

private:
    std::function m_func;
};
Run Code Online (Sandbox Code Playgroud)

如果模板类型可以在std :: function中使用它会很好,当我将指针传递给函数或std :: bind的结果时,它可以以某种方式推导出它.在C++中这样的事情是否可行.

Que*_*tin 9

嗯.我可能会或可能不会有过分杀戮.

#include <type_traits>
#include <utility>
#include <iostream>

template <class T>
struct RetWrapper {
    template <class Tfunc, class... Targs>
    RetWrapper(Tfunc &&func, Targs &&... args)
    : val(std::forward<Tfunc>(func)(std::forward<Targs>(args)...)) {}

    T &&value() { return std::move(val); }

private:
    T val;
};

template <>
struct RetWrapper<void> {
    template <class Tfunc, class... Targs>
    RetWrapper(Tfunc &&func, Targs &&... args) {
        std::forward<Tfunc>(func)(std::forward<Targs>(args)...);
    }

    void value() {}
};

template <class Tfunc, class Tbefore, class Tafter>
auto decorate(Tfunc &&func, Tbefore &&before, Tafter &&after) {
    return [

        func = std::forward<Tfunc>(func),
        before = std::forward<Tbefore>(before),
        after = std::forward<Tafter>(after)

    ] (auto &&... args) -> decltype(auto) {

        before(std::forward<decltype(args)>(args)...);
        RetWrapper<std::result_of_t<Tfunc(decltype(args)...)>> ret(
            func, std::forward<decltype(args)>(args)...
        );
        after(std::forward<decltype(args)>(args)...);

        return ret.value();
    };
}

/*
 * Tests
 */

float test1(float a, float b) {
    std::cout << "Inside test1\n";
    return a * b;
}

void test2() {
    std::cout << "Inside test2\n";
}

int i = 0;

int &test3() {
    return i;
}

int main() {

    auto test1Deco = decorate(
        test1,
        [] (float a, float b) {
            std::cout << "Calling test1 with " << a << " and " << b << '\n';
        },
        [] (float a, float b) {
            std::cout << "Called test1 with " << a << " and " << b << '\n';
        }
    );

    float c = test1Deco(3.5f, 5.1f);

    std::cout << "Yields " << c << '\n';

    auto test2Deco = decorate(
        test2,
        [] () {
            std::cout << "Calling test2\n";
        },
        [] () {
            std::cout << "Called test2\n";
        }
    );

    test2Deco();

    auto test3Deco = decorate(
        test3,
        [] () {
            std::cout << "Calling test3\n";
        },
        [] () {
            std::cout << "Called test3\n";
        }
    );

    auto &i2 = test3Deco();
    i2 = 42;

    std::cout << "Global i = " << i << '\n';

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Calling test1 with 3.5 and 5.1
Inside test1
Called test1 with 3.5 and 5.1
Yields 17.85
Calling test2
Inside test2
Called test2
Calling test3
Called test3
Global i = 42
Run Code Online (Sandbox Code Playgroud)


Giu*_*nco 8

只需要完整的模板,没有std :: function:

template< typename Func >
class FunctionDecorator
{
public:
  FunctionDecorator( Func func )
    : m_func( std::move(func) )
  {}

  void operator()()
  {
    // do some stuff prior to function call
    m_func();
    // do stuff after function call
  }

private:
  Func m_func;
};

template< typename Func >
FunctionDecorator<Func> decorate(Func func) {
  return FunctionDecorator<Func>(std::move(func));
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道,这是它的要求.如果你想要参数,你只需要使operator()成为一个模板:`template <typename ... Args> void operator()(Args && ... args){m_func(std :: forward <Args>(args) )...); }`.然后你也可以处理m_func返回一些东西的情况,使得这个东西任意复杂. (2认同)