1. 程式人生 > >AOP C++通用模板實現

AOP C++通用模板實現

has_member.h:

#ifndef __AOP_SRC_HAS_MEMBER_H__
#define __AOP_SRC_HAS_MEMBER_H__
#include <type_traits>

#define HAS_MEMBER_FUNCTION(member) \
template<typename T, typename ... Args> \
struct has_member_##member \
{ \
private: \
    template<typename U> \
    static auto test(void*) -> decltype(std::declval<U>().member(std::declval<Args>()...), std::true_type()); \
    \
    template<typename U>\
    static std::false_type test(...);\
    \
public:\
    static const bool value = decltype(test<T>(nullptr))::value;\
};

#endif

macros.h:

#ifndef __AOP_MACROS_H__
#define __AOP_MACROS_H__

#define AOP_NAMESPACE_BEGIN namespace aop {

#define AOP_NAMESPACE_END }

#endif

aspect.h:

#ifndef __AOP_SRC_ASPECT_H__
#define __AOP_SRC_ASPECT_H__
#include "has_member.h"
#include "macros.h"

AOP_NAMESPACE_BEGIN

HAS_MEMBER_FUNCTION(Before);
HAS_MEMBER_FUNCTION(After);

template<typename Func, typename... Args>
struct Aspect
{
    Aspect(Func&& func) : func_(std::forward<Func>(func)) {}
    Aspect(const Aspect&) = delete;
    Aspect& operator=(const Aspect&) = delete;

    template<typename T, typename = std::enable_if_t<has_member_Before<T, Args...>::value>>
    void InvokeBefore(T&& aspect, Args&&... args)
    {
        aspect.Before(std::forward<Args>(args)...);
    }

    void InvokeBefore(...) {}

    template<typename T, typename = std::enable_if_t<has_member_After<T, Args...>::value>>
    void InvokeAfter(T&& aspect, Args&&... args)
    {
        aspect.After(std::forward<Args>(args)...);
    }

    void InvokeAfter(...) {}

    template<typename T>
    void Invoke(Args&&... args, T&& aspect)
    {
        InvokeBefore(std::forward<T>(aspect), std::forward<Args>(args)...);
        func_(std::forward<Args>(args)...);
        InvokeAfter(std::forward<T>(aspect), std::forward<Args>(args)...);
    }

    template<typename Head, typename... Tail>
    void Invoke(Args&&... args, Head&& head, Tail&&... tail)
    {
        InvokeBefore(std::forward<Head>(head), std::forward<Args>(args)...);
        Invoke(std::forward<Args>(args)..., std::forward<Tail>(tail)...);
        InvokeAfter(std::forward<Head>(head), std::forward<Args>(args)...);
    }

private:
    Func func_;
};

template<typename T>
using identity_t = typename std::identity<T>::type;

template<typename... AP, typename Func, typename... Args>
void Invoke(Func&& func, Args&&... args)
{
    Aspect<Func, Args...> asp(std::forward<Func>(func));
    asp.Invoke(std::forward<Args>(args)..., identity_t<AP>()...);
}

template<typename... AP, typename Func, typename... Args>
void InvokeWithAspects(AP&&...ap, Func&& func, Args&&... args)
{
    Aspect<Func, Args...> asp(std::forward<Func>(func));
    asp.Invoke(std::forward<Args>(args)..., std::forward<AP>(ap)...);
}

AOP_NAMESPACE_END

#endif

test:

 

// aop.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <chrono>
#include <string>
#include "has_member.h"
#include "aspect.h"

using namespace std;

struct TimeElapsedAspect
{
    void Before(int i)
    {
        std::cout << "start timer" << std::endl;
        timer = std::chrono::system_clock::now();
    }

    void After(int i)
    {
        cout << "time elapsed: " << std::chrono::system_clock::duration(std::chrono::system_clock::now() - timer).count() << endl;
    }

private:
    std::chrono::system_clock::time_point timer{ std::chrono::system_clock::now() };
};

struct LoggingAspect
{
    LoggingAspect()
    {
        static int id = 0;
        std::cout << "LoggingAspect::construct -- id:" << id++ << std::endl;
    }

    void Before(int i)
    {
        std::cout << "entering" << std::endl;
    }

    void After(int i)
    {
        std::cout << "leaving" << std::endl;
    }
};

struct NoBeforeOrAfter
{
    NoBeforeOrAfter()
    {
        static int id = 0;
        std::cout << "NoBeforeOrAfter::construct -- id:" << id++ << std::endl;
    }

    void Before(const std::string&)
    {
    }

    void After(const std::string&)
    {
    }
};

void foo(int a)
{
    cout << "real HT function: " << a << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{

    aop::Invoke<NoBeforeOrAfter, LoggingAspect, TimeElapsedAspect>(&foo, 1);
    cout << "-----------------------" << endl;
    aop::Invoke<TimeElapsedAspect, NoBeforeOrAfter, LoggingAspect>(&foo, 1);
    cout << "-----------------------" << endl;
    aop::Invoke<LoggingAspect, LoggingAspect, NoBeforeOrAfter>(&foo, 1);
    cout << "-----------------------" << endl;

    LoggingAspect logging;
    TimeElapsedAspect timer;
    NoBeforeOrAfter no_before_or_after;

    aop::InvokeWithAspects<LoggingAspect, LoggingAspect, TimeElapsedAspect, NoBeforeOrAfter>(std::forward<LoggingAspect>(logging),
        std::forward<LoggingAspect>(logging),
        std::forward<TimeElapsedAspect>(timer),
        std::forward<NoBeforeOrAfter>(no_before_or_after),
        &foo, 1);

    system("pause");

    return 0;
}