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

https://blog.csdn.net/biqioso/article/details/83144944

https://blog.csdn.net/p942005405/article/details/84755007