目录
Promise概念
QtPromise开源模板库
QtPromise模板库中所使用的设计模式
1. QtPromise中的构建模式
2. QtPromise中的装饰模式
QtPromise模板库中使用到的元编程技巧
1. 模板元函数
2. 全特化&偏特化构建if-then-else
3. Type Traits 类型特征
4. SFINAE
QtPromise源码分析和实现思想
1. QtPromise的UML 时序图
2. QtPromise源码分析
设计模式与元编程的混合
1. 元编程与单例模式sampleCode
2. 元编程与其他模式
Promise是一种异步编程的解决方案.
Promises 是用于传递异步计算结果的回调的替代方法.
使用Qt框架的朋友如果对异步编程有需求,建议可使用此模板库对异步操作做处理。
github地址: GitHub - simonbrunel/qtpromise: Promises/A+ implementation for Qt/C++
使用手册地址: Getting Started | QtPromise
下文对QtPromise模板库的源码做一些分析以及其所用到的一些CPP的技巧共同做些探讨。
本文并不会教你如何更好的使用QPromise而是分享其内部实现的思想和流程。
a. 一般我们在构造复杂对象时为了简化初始化通常会把多个成员属性拆分成多个set/with成员方法来用于构造对象。
b. 同样为了让QPromise的调用更加符合Promise风格和达到链式调用的目的。QPromise类对外接口也都是基于此模式的变种。
QPromise 父类QPromiseBase源码示例:
// 摘自QPromise类的部分成员函数声明
template
class QPromiseBase {
template
inline typename QtPromisePrivate::PromiseHandler::Promise
then(const TFulfilled& fulfilled, const TRejected& rejected) const;
template
inline typename QtPromisePrivate::PromiseHandler::Promise
then(TFulfilled&& fulfilled) const;
template
inline typename QtPromisePrivate::PromiseHandler::Promise
fail(TRejected&& rejected) const;
template
inline QPromise finally(THandler handler) const;
template
inline QPromise tap(THandler handler) const;
template
inline QPromise tapFail(THandler handler) const;
template
inline QPromise timeout(int msec, E&& error = E{}) const;
template
inline QPromise timeout(std::chrono::milliseconds msec, E&& error = E{}) const;
inline QPromise delay(int msec) const;
inline QPromise delay(std::chrono::milliseconds msec) const;
inline QPromise wait() const;
};
我们看到QPromiseBase大部分函数都返回了QPromise实例对象符合构建模式的思想但与构建模式又存在一定区别,构建模式的设置方法是作用于同一对象且返回的也是同一对象。 但QPromiseBase中每次返回是一个新的Promise实例对象。
a. 业务逻辑请使用组合方式来实现。 -- 摘自微服务架构设计模式一书
组合模式带来的好处:
b. 基于PromiseResolver的装饰
我们先来看看PromiseResolver类的源码
template
class PromiseResolver
{
public:
PromiseResolver(QtPromise::QPromise promise) : m_d{new Data{}}
{
m_d->promise = new QtPromise::QPromise{std::move(promise)};
}
template
void reject(E&& error)
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->reject(std::forward(error));
promise->m_d->dispatch();
release();
}
}
void reject()
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->reject(QtPromise::QPromiseUndefinedException{});
promise->m_d->dispatch();
release();
}
}
template
void resolve(V&& value)
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->resolve(std::forward(value));
promise->m_d->dispatch();
release();
}
}
void resolve()
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->resolve();
promise->m_d->dispatch();
release();
}
}
private:
struct Data : public QSharedData
{
QtPromise::QPromise* promise = nullptr;
};
QExplicitlySharedDataPointer m_d;
void release()
{
Q_ASSERT(m_d->promise);
Q_ASSERT(!m_d->promise->isPending());
delete m_d->promise;
m_d->promise = nullptr;
}
};
//
template
class QPromiseResolve
{
public:
QPromiseResolve(QtPromisePrivate::PromiseResolver resolver) : m_resolver{std::move(resolver)}
{
qDebug() << "QPromiseResolve";
}
~QPromiseResolve() {
qDebug() << "~QPromiseResolve";
}
template
void operator()(V&& value) const
{
m_resolver.resolve(std::forward(value));
}
void operator()() const { m_resolver.resolve(); }
private:
mutable QtPromisePrivate::PromiseResolver m_resolver;
};
template
class QPromiseReject
{
public:
QPromiseReject(QtPromisePrivate::PromiseResolver resolver) : m_resolver{std::move(resolver)}
{ }
template
void operator()(E&& error) const
{
m_resolver.reject(std::forward(error));
}
void operator()() const { m_resolver.reject(); }
private:
mutable QtPromisePrivate::PromiseResolver m_resolver;
};
从源码分析我们知道PromiseResolver的功能比较简单单一,持有一个QPromise实例, 对客户代码提供操作成功和失败的方法进而把外部操作结果转发到持有的promise实例内部处理。
QPromise为了达到更加简单易用的方式(更加符合现代的函数式编程范式)以及语义上更加符合Promise风格,继续定义了QPromiseResolve&QPromiseReject类用来单独处理成功和失败的情况。 我们看这三者类并不是教科书上的标准的装饰模式, 但实际上QPromiseResolve&QPromiseReject类的实现组合PromiseResolver实例, 重载调用()运算符(使其成为一个可调用对象)内部转发对PromiseResolver的调用基本符合了装饰模式的思想只是缺少了基类接口的存在,对外缺少统一调用接口但()操作符的重载很好的弥补了这一缺陷。
PromiseResolver&QPromiseResolve&QPromiseReject UML 类图
从Promise的使用情况看, 对于客户代码只需要关心在处理结果时对于QPromiseResolve&QPromiseReject调用操作,由于QPromiseResolve&QPromiseReject类组合PromiseResolver,持有QPromise对象且存在整个QPromise执行链中。个人在这将PromiseResolver&QPromiseResolve&QPromiseReject 统一称作QPromise上下文类。
由于QtPromise是一个轻量级的模板库,内部用到了大量模板元技术。 故在分析QtPromise源码前我们需对QtPromise中用到的CPP模板元技巧概念做些介绍
a. 元函数函数特征&定义
b. 值元函数&型别元函数
值元函数通常返回一个值
template
class ValueMetaFunction {
static constexpr int value = 100;
};
我们声明&定义了一个名为ValueMetaFunction的元函数,返回了一个value为int的值.
值元函数的plus版本
template
class ValueMetaFunction {
static constexpr auto value = 100;
};
template
class ValueMetaFunction {
static constexpr T value = value
};
型别元函数通常返回一个类型
template
class TypeMetaFunction {
using type = T;
};
声明&定义一个名为TypeMetaFunction的元函数,返回了一个型别为T的type类型
c. 元函数的调用
针对于上述的示例代码我们现在来获取元函数的返回值
ValueMetaFunction::value
ValueMetaFunction::value
TypeMetaFunction::type --> typename TypeMetaFunction::type
我们在调用元函数返回值时一般书写都比较长,阅读起来也比较不友好。CPP提供了using关键字可以用于定义更加便捷的调用方式。
使用using关键字为模板(元函数)定义别名。
通常value元函数使用以 _v结尾的变量模板
template
using value_v = ValueMetaFunction::value
通常type 元函数使用以 _t结尾的变量模板
template
using type_t = typename ValueMetaFunction::type
使用便捷的调用方式
value_v
type_t
d. 一个有用的元函数
// STRUCT TEMPLATE integral_constant
template
struct integral_constant {
static constexpr _Ty value = _Val;
using value_type = _Ty;
using type = integral_constant;
constexpr operator value_type() const noexcept {
return value;
}
_NODISCARD constexpr value_type operator()() const noexcept {
return value;
}
};
// ---摘自MSVC xtr1commom文件
integral_constant应用于在系统位数判断上
static const std::uint64_t default_buffer_size =
std::conditional,
std::integral_constant
>::type::value
这样编码的优势:
模板的全特化与偏特化特性构建出了元编程中的条件判断
模板偏特化&全特换的示例:
// 标准模板
template
struct Sample {};
// 对于T为指针的偏特化
template
struct Sample {};
// 对于T为int的偏特化
template
struct Sample {};
// 对于T&U都为int类型的全特化
template<>
struct Sample {};
声明if-then-else:
template< bool CONDITION, class THEN, class ELSE > struct IF {};
template struct IF< false, THEN, ELSE > {typedef ELSE TEST;};
template struct IF< true, THEN, ELSE > {typedef THEN TEST;};
if-then-else SampleCode:
template< bool Condition >
class IF {
public:
static inline void EXEC(){std::cout << "Statement is true";}
};
// 全特化IF模板,当模板参数为false时匹配该版本
class IF< false > {
public:
static inline void EXEC(){std::cout << "Statement is false";}
};
std::cout << IF::EXEC()<< std::endl;
a. type traits是什么?
b. MSVC中的type_traits文件中定义了大量常用的类型特征模板
下图摘自
具体说明及用法大家可以点击链接进行查看。上述类型特性模板在常见的模板设计程序中会经常有使用到。
c. call_traits
示例
// CLASS TEMPLATE binder1st
template
class binder1st : public unary_function { // functor adapter _Func(stored, right)
public:
using _Base = unary_function;
using argument_type = typename _Base::argument_type;
using result_type = typename _Base::result_type;
binder1st(const _Fn& _Func, const typename _Fn::first_argument_type& _Left) : op(_Func), value(_Left) {}
// @1
result_type operator()(const argument_type& _Right) const {
return op(value, _Right);
}
result_type operator()(argument_type& _Right) const {
return op(value, _Right);
}
protected:
_Fn op;
typename _Fn::first_argument_type value; // the left operand
};
// -- 摘自MSVC functional头文件
MSVC实现的binder1st 结构中存在着如果代码段@1中 argument_type如果是个引用类型,则binder1st重载()调用运算符存在引用引用的的问题。 这在C++中是不被允许的
call_traits 工具 -- 摘自boost程序库
call_traits 的目的是确保像“引用引用”这样的问题永远不会发生,并且以最有效的方式传递参数。
template
struct ct_imp2 {
typedef const T& param_type;
};
template
struct ct_imp2 {
typedef const T param_type;
};
template
struct ct_imp {
typedef const T& param_type;
};
template
struct ct_imp {
typedef typename ct_imp2::param_type param_type;
};
template
struct ct_imp {
typedef typename ct_imp2::param_type param_type;
};
template
struct ct_imp {
typedef const T param_type;
};
template
struct call_traits
{
public:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef typename ct_imp<
T,
::boost::is_pointer::value,
::boost::is_arithmetic::value,
::boost::is_enum::value
>::param_type param_type;
};
template
struct call_traits
{
typedef T& value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T& param_type; // hh removed const
};
template
struct call_traits
{
typedef T& value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T& param_type; // hh removed const
};
// 摘自boost程序库 call_traits.hpp 部分
binder1st 对于调用操作符的重载最终可修改为
result_type operator()(typename call_traits::param_type _Right) const {
return op(value, _Right);
}
b. QtPromise中的型别特性的应用
QtPromise中定义了ArgsTraits元函数用于提取函数的形参列表元信息。
template
struct ArgsTraits
{
using types = std::tuple;
// 返回函数参数列表第一个形参的类型
using first = typename std::tuple_element<0, types>::type;
// 返回函数参数列表的形参数量
static const size_t count = std::tuple_size::value;
};
// 全特化参数列表为空的情况
template<>
struct ArgsTraits<>
{
using types = std::tuple<>;
using first = void;
static const size_t count = 0;
};
// -- 摘自 qpromiseglobal.h 头文件
定义ArgsTraits的扩展类ArgsOf元函数,由ArgsTraits的声明可知,ArgsTraits元函数接收的是有个类型参数包。 扩展类ArgsOf的作用则用于收集函数列表类型信息。
// 标准的ArgsOf类型的声明定义
template struct ArgsOf : public ArgsTraits<> { };
// 对nullptr_t的偏特化
template<> struct ArgsOf : public ArgsTraits<>{ };
// 对operator () 成员函数指针偏特化
template
struct ArgsOf::value>::type>: public ArgsOf { };
// 对引用类型的偏特化
template struct ArgsOf : public ArgsOf { };
// 对右值类型的偏特化
template struct ArgsOf : public ArgsOf { };
// 对可调用类型的偏特化
template struct ArgsOf : public ArgsTraits { };
// 对函数指针的偏特化
template struct ArgsOf : public ArgsTraits { };
// 对成员函数指针偏特化
template struct ArgsOf : public ArgsTraits { };
// 对const的成员函数指针偏特化 @7
template struct ArgsOf : public ArgsTraits { };
// 对volatile的成员函数指针偏特化 @8
template struct ArgsOf : public ArgsTraits { };
// 偏特化类型T为 const volatile的成员函数指针 @9
template struct ArgsOf : public ArgsTraits { };
// -- 摘自 qpromiseglobal.h 头文件
我们看到ArgsOf对于大部分函数指针类型的情况都进行了偏特化从而对特定的函数形参列表参数包进行提取,进而传递给其父类。完成对函数形参列表信息的提取。
我们其实发现ArgsOf作用紧紧是用于提取函数的形参列表类型,至于类的成员函数是否是 const、volatile、const volatile等类型是不关心的。但为了满足类的成员函数所有类型的提取则必须尽可能的偏特化出所有成员函数类型的ArgsOf版本 见代码段@7& 8 & 9。细心的读者可能会发现ArgsOf对于类的成员函数形参列表类型的元信息提取其实是不全的,因为ArgsOf并没有偏特化全部的成员函数类型。例如 const&、const&&、const volatile&、const volatile&&、volatile&、volatile&&成员函数类型就没有进行偏特化, 对于这一类型的成员函数类型在编译器实例化ArgsOf时会去匹配标准的ArgsOf版本所以函数形参列表会作为空处理。
如果你的项目中有上述提到的未偏特化的成员函数则在使用QPromise时就出现错误了。 我们该如何去优化以下ArgsOf呢?
项目开发中我们可以提供一个基础的大而全的type_traits, 用于提取裸函数类型。 无论你是否使用QtPromise模板库, 至少在项目其他需求中也是可以作为一个基础类而存在的。
提供一个is_const_or_volatile_member_function 成员函数类型特征工具类, 声明定义如下:
template
struct is_const_or_volatile_member_function : std::false_type { };
template
struct is_const_or_volatile_member_function : std::true_type{
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
template
struct is_const_or_volatile_member_function : std::true_type {
using type = R(T::*)(Args...);
};
is_const_or_volatile_member_function偏特化出了成员函数的所有的类型, 且继承与std::false_type or std::true_type用于给出一个bool值判断传入的类型是否为成员函数类型。最终返回一个裸成员函数指针类型type(此处裸代表 成员函数是非 const、 const&、const&&、const volatile、const volatile&、const volatile&&、volatile、volatile&、volatile&& 类型)
is_const_or_volatile_member_function使用:
这里对于之前ArgsOf定义的代码段@7、8、9 统一可以修改为下图的代码段@2。 这样可以由is_const_or_volatile_member_function元函数去提取所有的非裸成员函数类型也节省了ArgsOf偏特化的版本数量。
// @1
// 对指针成员函数类型的偏特化
template
struct ArgsOf : public ArgsTraits
{
static constexpr char* value = "R(T::*)(Args...)";
};
// @2
// 对 const、 const&、const&&、const volatile、const volatile&、
// const volatile&&、volatile、volatile&、volatile&& 成员函数指针偏特化
template
struct ArgsOf ::value> >:
public ArgsOf::type>
{
static constexpr char* value = "R(*)(Args...) const or volatile";
};
此处我们来验证下对于优化后ArgsOf的使用
use sample code:
qDebug() << ArgsOf::value;
qDebug() << ArgsOf::value;
qDebug() << ArgsOf::value;
qDebug() << ArgsOf::value;
qDebug() << ArgsOf::value;
qDebug() << ArgsOf::value;
输出:
R(T::*)(Args...)
R(*)(Args...) const or volatile
R(*)(Args...) const or volatile
R(*)(Args...) const or volatile
R(*)(Args...) const or volatile
R(*)(Args...) const or volatile
从输出我们可以分析出非裸成员函数指针类型都匹配到上述代码段@2的ArgsOf偏特化版本,裸成员函数类型匹配到了代码段@1的ArgsOf偏特化版本。至此我们完成了对QtPromise模板库中ArgsOf的偏特化类的成员函数类型不足的优化。
a. SFINAE 是什么?
b. SFINAE 能做什么?
c. SFINAE在QtPromise中的应用
检查一个类中是否函数成员函数
template
struct HasCallOperator
{
template
static char check(decltype(&U::operator(), char(0)));
template
static char (&check(...))[2];
static const bool value = (sizeof(check(0)) == 1);
};
// -- 摘自qpromiseglobal.h文件
QPromiseBase构造函数重载
template::count == 1, int>::type = 0>
inline QPromiseBase(F resolver);
template::count != 1, int>::type = 0>
inline QPromiseBase(F resolver);
根据实参类型中的形参列表数量编译器来进行最佳的构造函数生成。
下面我结合此时序图对QtPromise 源码的主要流程进行分析
a. QPromise的构造&生命周期
先看一个基本的使用QPromise Sample Code:
{
QPromise promise = QPromise([](QPromiseResolve resolve, QPromiseReject reject) {
// @1
resolve(100)
}).then([](int) -> std::string {
return "100";
});
}
上述代码段构建了一个基本的Promise链式调用并返回链式最后一个QPromise实例,不知道大家在使用QPromise时有没有这样的一个疑问,就是在上述代码段执行完成后promise实例都销毁了。 它是如何保证异步继续执行下有个then方法函数体的??? 随着我们对QPromise对象的构造分析慢慢来解答这个问题。
QPromise构造函数分析
template
class QPromiseBase
{
public:
using Type = T;
// @1
template::count == 1, int>::type = 0>
inline QPromiseBase(F resolver) : m_d{new QtPromisePrivate::PromiseData{}}
{
// @6
QtPromisePrivate::PromiseResolver resolver{*this};
try {
// @4
callback(QPromiseResolve(resolver));
} catch (...) {
resolver.reject(std::current_exception());
}
}
// @2
template::count != 1, int>::type = 0>
inline QPromiseBase(F resolver) : m_d{new QtPromisePrivate::PromiseData{}}
{
// @7
QtPromisePrivate::PromiseResolver resolver{*this};
try {
// @5
callback(QPromiseResolve(resolver), QPromiseReject(resolver));
} catch (...) {
resolver.reject(std::current_exception());
}
}
};
template
class QPromise : public QPromiseBase
{
public:
// @3
template
QPromise(F&& resolver) : QPromiseBase(std::forward(resolver)) {
}
};
template
void resolve(V&& value)
{
auto promise = m_d->promise;
if (promise) {
Q_ASSERT(promise->isPending());
promise->m_d->resolve(std::forward(value));
promise->m_d->dispatch();
release();
}
}
相信看到此处我们知道QtPromise内部是如何保证其生命周期了。
QPromise then核心函数分析
then提供了接收下一步(异步)处理的函数入口(下文中称nextPromise对象)
then函数体源码
template
template
inline typename QtPromisePrivate::PromiseHandler::Promise
QPromiseBase::then(const TFulfilled& fulfilled, const TRejected& rejected) const
{
using namespace QtPromisePrivate;
// @1
using PromiseType = typename PromiseHandler::Promise;
// @2
PromiseType next([&](const QPromiseResolve& resolve,
const QPromiseReject& reject) {
// @3
m_d->addHandler(PromiseHandler::create(fulfilled, resolve, reject));
m_d->addCatcher(PromiseCatcher::create(rejected, resolve, reject));
});
if (!m_d->isPending()) {
m_d->dispatch();
}
return next;
}
template
template
inline typename QtPromisePrivate::PromiseHandler::Promise
QPromiseBase::then(TFulfilled&& fulfilled) const
{
return then(std::forward(fulfilled), nullptr);
}
// PromiseHandler标准版
template::first>
struct PromiseHandler
{
using ResType = typename invoke_result::type;
using Promise = typename PromiseDeduce::Type;
template
static std::function
create(const THandler& handler, const TResolve& resolve, const TReject& reject)
{
return [=](const T& value) {
PromiseDispatch::call(resolve, reject, handler, value);
};
}
};
将PromiseHandler构建的可调用对象保存在当前的成员属性QPromiseData中
返回Promise对象继续以链式的方式接收下一个处理者
c. QPromiseData结构&Promise链式内存模型
QPromise 类从其父类PromiseBase继承了唯一的数据属性成员m_d。
QExplicitlySharedDataPointer> m_d;
QPromiseData结构, 下图源码仅给出了Promise成员属性,
template
class PromiseDataBase : public QSharedData {
public:
using Handler = std::pair, std::function>;
using Catcher = std::pair, std::function>;
protected:
mutable QReadWriteLock m_lock;
private:
bool m_settled = false;
// 异步事件完成后下一步需要调用的可调用对象集合(及nextPromise的封装)
QVector m_handlers;
// 出错处理情况
QVector m_catchers;
PromiseError m_error;
};
template
class PromiseData : public PromiseDataBase {
using Handler = typename PromiseDataBase::Handler;
private:
// 当前Promise处理(返回)的值交由PromiseValue自动管理其生命周期
PromiseValue m_value;
};
// 全特化QPromise返回值类型为void的case
template<>
class PromiseData : public PromiseDataBase
{
using Handler = PromiseDataBase::Handler;
}
// 对数据T使用RAII手法来管理其生命周期
template
class PromiseValue
{
public:
PromiseValue() { }
PromiseValue(const T& data) : m_data(QSharedPointer::create(data)) { }
PromiseValue(T&& data) : m_data(QSharedPointer::create(std::forward(data))) { }
bool isNull() const { return m_data.isNull(); }
const T& data() const { return *m_data; }
private:
QSharedPointer m_data;
};
从Promise类的属性成员 QPromiseData的结构我们可以给出其内存模型
QPromiseResolve&QPromiseReject为PromiseResolver的装饰对象。
PromiseResolver是一个携带QPromise对象的上下文,即handler与catcher callable对象中成员属性resolve、reject装饰对象分别又指向了QPromiseData对象即形成了QPromise 链式内存模式。
d. QPromise 上下文类的作用
e. Qt消息循环实现Promise非阻塞调用
template
static void qtpromise_defer(F&& f, const QPointer& thread)
{
using FType = typename std::decay::type;
struct Event : public QEvent
{
Event(FType&& f) : QEvent{QEvent::None}, m_f{std::move(f)} { }
Event(const FType& f) : QEvent{QEvent::None}, m_f{f} { }
~Event() override { m_f(); }
FType m_f;
};
if (!thread || thread->isFinished()) {
// Make sure to not call `f` if the captured thread doesn't exist anymore,
// which would potentially result in dispatching to the wrong thread (ie.
// nullptr == current thread). Since the target thread is gone, it should
// be safe to simply skip that notification.
return;
}
QObject* target = QAbstractEventDispatcher::instance(thread);
if (!target && QCoreApplication::closingDown()) {
// When the app is shutting down, the even loop is not anymore available
// so we don't have any way to dispatch `f`. This case can happen when a
// promise is resolved after the app is requested to close, in which case
// we should not trigger any error and skip that notification.
return;
}
Q_ASSERT_X(target, "postMetaCall", "Target thread must have an event loop");
QCoreApplication::postEvent(target, new Event{std::forward(f)});
}
Promise完成异步调用最终函数体,依赖Qt异步消息机制。 下一个待处理的可调用对象(Lambda表达式)封装着nextPromise的上下文对象。
F: HandlerCallable
Event: 自定义QEvent携带Callable基于消息循环异步调用nextPromise
thread: 保证线程单一性
对于喜欢元编程的读写朋友在这里推荐去阅读Loki 库的源码,其中对于元编程的各项技巧都有深入涉及。Loki主要使用模板元编程去实现通用的设计模式。看看模板元编程与设计模式在一起组合会碰撞出什么样的火花。 (#^.^#)
策略结构的定义
对象创建策略结构
template struct CreateUsingNew {
static T* Create() {
return new T;
}
static void Destroy(T* p) {
delete p;
}
};
对象生命周期策略结构
template
struct DefaultLifetime {
static void ScheduleDestruction(T*, atexit_pfn_t pFun) {
std::atexit(pFun);
}
static void OnDeadReference() {
throw std::logic_error("Dead Reference Detected");
}
};
单例构造模板类的定义
模板单例类接收两个默认的创建对象以及生命周期管理类型。 实例化时用户代码可重新扩展该策略类型。
以上内容摘自Loki库,为做简单示例有简化该单例模式构造模板类。
Loki template Library库还实现了以下模板元与设计模式的混合
至于具体的讲解大家可以阅读modern C++ programming 一书. 此书就是基于Loki库来编写的。
结尾
1. 读优秀框架源码是为了更好的使用以及修改。
2. 学习优秀的编码思想使得自己不断的成长。