0. 简介
模板模式是行为模式的最后一章,也是我们设计模式的最后一章。模板模式是C++高级用法中不可或缺的一部分,也是作为我这种SLAMer必不可少的需要大量使用的模式。在Ceres,G2o中都可以看到这样的用法。它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
1. 模板模式示意图
我们可以看到模板模式结构是非常简单的设计模式。通过复用模板抽象类的方法能够避免大量的重复性代码。
模板方法基于继承机制, 它允许你通过扩展子类中的部分内容来改变部分算法。 策略模式基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。 模板方法在类层次上运作, 因此它是静态的。 策略在对象层次上运作, 因此允许在运行时切换行为。
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
模板是一种对类型进行参数化的工具;
通常有两种形式:函数模板和类模板;
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
2. 代码分析
这是我们观察者模式的模板代码,我们可以看到模板类可以与其他的形式组合,从而有效地扩展功能
其中“…”可以表示函数接收可变参数,或是捕获任意类型异常
“std::function<void()>”作为注册方式,一个模板类对象,它可以用一个函数签名为void()的可调用对象来进行初始化,这是回调函数常用的做法</void()>
/* 实现事件的信号类 */
template <typename... TFuncArgs>
class Signal {
public:
using Callback = std::function<void(TFuncArgs...)>;
/* 连接类, 一旦结束,Disconnect()将被自动调用。
*/
class SignalConnection {
private:
friend class Signal;
/* 只允许类Signal创建连接 */
SignalConnection(Signal& signal, int id) noexcept:id(id), signal(signal) {}
public:
/* C++11 成员函数声明新特性: = delete,从逻辑语义上禁止了对于SignalConnection类拷贝构造函数和赋值运算符*/
SignalConnection(const SignalConnection& copy) = delete;
/* 如果没有复制构造函数,则不能返回SignalConnection,除非提供一个move构造函数。 */
SignalConnection(SignalConnection&& toMove) noexcept : id(toMove.id), signal(toMove.signal),disconnected(toMove.disconnected) {}
~SignalConnection() {
Disconnect();
}
int id;
Signal& signal;
bool disconnected = false;
void Disconnect() {
if (disconnected)
return;
disconnected = true;
signal.Disconnect(*this);
}
};
/* 返回连接对象,连接对象一旦超出作用域将自动断开连接 */
SignalConnection Connect(Callback callback) {
callbacks.push_back(std::pair<int, Callback>(idRoller++, callback));
return SignalConnection(*this, idRoller - 1);
}
void Invoke(TFuncArgs... args) {
for (auto& con : callbacks) {
(con.second)(args...);
}
}
void operator()(TFuncArgs... args) {
Invoke(args...);
}
private:
/* ID Counter.
使用id查找连接对应的回调函数,因为std::function的操作符==并不像想象的那样工作。*/
int idRoller = 0;
std::list<std::pair<int, Callback>> callbacks;
void Disconnect(SignalConnection& t) {
callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), [&](auto& pCallback) {
return pCallback.first == t.id;
}), callbacks.end());
}
};
void TestFunc1(int t) {
cout << "Func1" << endl;
}
void TestFunc2(int t,string someArg) {
cout << "Func2" << endl;
}
int main(){
using TestDelegate = Signal<int>;
TestDelegate testEvent;
TestDelegate::SignalConnection testCon1 = testEvent.Connect(&TestFunc1);
TestDelegate::SignalConnection testCon2 = testEvent.Connect(std::bind(TestFunc2 ,std::placeholders::_1, "arg")); //用bind去绑定参数
auto testCon3 = testEvent.Connect(&TestFunc1); //用auto简化声明
testEvent(1);
...
3.参考链接
https://blog.csdn.net/u013288190/article/details/120020405
评论(0)
您还未登录,请登录后发表或查看评论