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;
}