使用C++实现的轻量级的Qt信号与槽功能

Signal Vector

SV介绍

本工程使用C++11实现的轻量级信号与槽功能,用于在实际编程中的代码解耦。

工程代码仅由 sv.hpp ,实际工程源码在200行左右,通俗易懂。

SV使用

1.信号的定义:

​ sv<参数> 信号名称; /// 信号参数不支持左值引用

2.槽函数

​ 成员函数

​ 全局函数

​ 匿名函数

3.信号与槽的关联

​ connect(信号发送者,信号,信号接收者,槽函数,同步/异步);
​ connect(信号发送者,信号,槽函数,同步/异步);

4.信号发送

​ emit 信号(参数);

5.断开所有信号

​ disconnect(信号发送者,信号);

6.断开单个信号

​ 由于很少会使用,已删除单个信号的断开;

注意:信号与槽的参数类型必须严格匹配,否则不能连接成功

示例:

#include "sv.hpp"

class Server
{
signals:								/// 如果是Qt工程中使用,则需要将signals改成public,因为与Qt的signals关键字冲突
	sv<const Student&,int>	dataChanged;			/// 定义两个参数的dataChanged信号,等价于Qt的void dataChanged(const Student&,int)
	sv<const std::string&> 	newConnection;			/// 定义带一个参数的newConnection信号,等价于Qt的 void newConnection(const std::string&)
	sv<>			finished;				/// 定义无参finished信号,等价于Qt的 void finished();

public:
	/// 其他属性或函数
}

class Client
{
public slots:
	void onServerFinished()
	{
		/*处理工作*/
	}
	

	void onNewConnection(const std::string&)
	{
		/*处理工作*/
	}
	
	void onDataChanged(const Student&,int)
	{
		/*处理工作*/
	}

}

class Application
{
	Server 	server;
	Client 	client;
public:
	Application()
	{
		Sv::connect(&server,&Server ::dataChanged,&client,&Client::onDataChanged);
		Sv::connect(&server,&Server::finished,&client,&Client::onServerFinished,Sv::QueuedConnection);	/// 异步调用,默认为Sv::DirectConnection同步调用
		/*其他信号与槽的关联*/
	}
	~Application()
	{
		SvQueue::exec();			/// 等待线程正常退出,必须在程序结束前调用
	}

	void run()
	{
		/// 信号发送
		emit dataChanged(参数...);
		emit newConnection(参数...);
		emit finished();
	}

}

int main(int argc,char* argv[])
{
	Application app;
	app.run();
	

	return 0;

}

Signal Vector源码

#ifndef SV_HPP
#define SV_HPP 

/*************************************WRITE BY LJX*****************************************/

#include <vector>
#include <thread>
#include <deque>
#include <mutex>
#include <functional>
#include <condition_variable>

#ifndef slots
#define slots
#endif

#ifndef signals
#define signals        public
#endif

#ifndef emit
#define emit
#endif

/// 命名空间 Sv
#ifndef SV_NAMESPACE
#define SV_NAMESPACE Sv
#endif

namespace SV_NAMESPACE{

enum Connected{ DirectConnection,QueuedConnection };

template<unsigned int Size> struct SvImp;
template<> struct SvImp<0>{
    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),receiver)});
    }

    /// 支持匿名函数
    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot))});
    }

    /// 支持全局函数
    template<typename Sender,typename Signal,typename Slot>
    static inline void imp(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)
    {
        (sender->*signal).push_back({t,std::bind(slot)});
    }
};

#define GENERATOR(size,...)\
    template<> struct SvImp<size>{\
        template<typename Sender,typename Signal,typename Receiver,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),receiver,__VA_ARGS__)});\
        }\
        template<typename Sender,typename Signal,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(std::forward<Slot>(slot),__VA_ARGS__)});\
        }\
        template<typename Sender,typename Signal,typename Slot>\
        static inline void imp(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)\
        {\
            using namespace std::placeholders;\
            (sender->*signal).push_back({t,std::bind(slot,__VA_ARGS__)});\
        }\
    };
GENERATOR(1,_1)
GENERATOR(2,_1,_2)
GENERATOR(3,_1,_2,_3)
GENERATOR(4,_1,_2,_3,_4)
GENERATOR(5,_1,_2,_3,_4,_5)
GENERATOR(6,_1,_2,_3,_4,_5,_6)
GENERATOR(7,_1,_2,_3,_4,_5,_6,_7)
GENERATOR(8,_1,_2,_3,_4,_5,_6,_7,_8)
GENERATOR(9,_1,_2,_3,_4,_5,_6,_7,_8,_9)
GENERATOR(10,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10)
GENERATOR(11,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11)
GENERATOR(12,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12)
GENERATOR(13,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13)
GENERATOR(14,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14)
GENERATOR(15,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15)
GENERATOR(16,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_14,_16)
GENERATOR(17,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17)
GENERATOR(18,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18)
GENERATOR(19,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19)
GENERATOR(20,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20)
GENERATOR(21,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21)
GENERATOR(22,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22)
GENERATOR(23,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23)
GENERATOR(24,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24)
GENERATOR(25,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25)
GENERATOR(26,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26)
GENERATOR(27,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27)
GENERATOR(28,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28)
GENERATOR(29,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29)
#undef GENERATOR

template<typename Sender,typename Signal,typename Receiver,typename Slot>
inline void connect(Sender* sender,Signal signal,Receiver* receiver,Slot slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),receiver,std::forward<Slot>(slot),t);
}

/// 支持匿名函数
template<typename Sender,typename Signal,typename Slot>
inline void connect(Sender* sender,Signal signal,Slot&& slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),std::forward<Slot>(slot),t);
}

/// 支持全局函数
template<typename Sender,typename Signal,typename Slot>
inline void connect(Sender* sender,Signal signal,Slot* slot,Connected t = DirectConnection)
{
    SvImp<(sender->*signal).Parmers>::imp(sender,std::forward<Signal>(signal),slot,t);
}

template<typename Sender,typename Signal>
inline void disconnect(Sender* sender,Signal signal)
{
    (sender->*signal).clear();
}

}

class SvQueue
{
    using Tp     = std::function<void()>;
    using Locker = std::unique_lock<std::mutex>;

    bool                                flag;
    bool                                terminal;
    std::mutex                          mutex;
    std::condition_variable             cv;
    std::thread                         thread;
    std::deque<Tp>                      queue;
public:
    static SvQueue& instance()
    {
        static SvQueue svQueue;
        return svQueue;
    }

    static void exec()
    {
        SvQueue::instance().wait();
    }

public:
    void enqueue(Tp tp)
    {
        Locker locker(mutex);
        queue.push_back(tp);
        cv.notify_one();
    }

    Tp dequeue()
    {
        Locker locker(mutex);
        Tp tp = queue.front();
        queue.pop_front();
        return tp;
    }

protected:
    SvQueue()
    {
        flag = true;
        terminal = true;
        thread = std::thread(&SvQueue::run,this);
    }

    ~SvQueue()
    {
        wait();
    }

protected:
    void wait()
    {
        flag = false;
        cv.notify_one();
        if(thread.joinable()){
            thread.join();
        }
    }

    void terminate()
    {
        terminal = false;
        wait();
    }

protected:
    void run()
    {
        while (terminal)
        {
            {
                Locker locker(mutex);
                cv.wait(locker, [this]{ return !queue.empty() || !flag; });
                if(queue.size() == 0){
                    if(flag == false){
                        break;
                    }else{
                        continue;
                    }
                }
            }

            Tp tp = dequeue();
            tp();
        }
    }
};

template<typename... Args>
class sv : protected std::vector<std::pair<char,std::function<void(Args...)>>>
{
    using Tp                                = std::pair<char,std::function<void(Args...)>>;
    using Base                              = std::vector<Tp>;
    static constexpr unsigned int Parmers   = sizeof...(Args);

    template<unsigned int Size> friend struct SV_NAMESPACE::SvImp;

    template<typename Sender,typename Signal,typename Receiver,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Receiver* receiver,Slot slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Slot&& slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal,typename Slot>
    friend void SV_NAMESPACE::connect(Sender* sender,Signal signal,Slot* slot,SV_NAMESPACE::Connected t);

    template<typename Sender,typename Signal>
    friend void SV_NAMESPACE::disconnect(Sender* sender,Signal signal);

    using Locker = std::unique_lock<std::mutex>;
    std::mutex                          mutex;
public:
    template<typename... Params>
    inline void operator()(Params&&... parmers)
    {
        Locker   locker(mutex);
        typename Base::const_iterator it  = this->begin();
        typename Base::const_iterator end = this->end();
        while(it != end){
            switch (it->first)
            {
            case SV_NAMESPACE::DirectConnection:
                it->second(std::forward<Params>(parmers)...);
                break;
            case SV_NAMESPACE::QueuedConnection:
                SvQueue::instance().enqueue([=](){ it->second(parmers...); });
                break;
            }
            ++it;
        }
    }

protected:
    sv& operator=(sv&&)         = delete;
    sv& operator=(const sv&)    = delete;

protected:
    void clear()
    {
        Locker locker(mutex);
        Base::clear();
    }

    void push_back(const Tp& tp)
    {
        Locker locker(mutex);
        Base::push_back(tp);
    }

    void push_back(Tp&& tp)
    {
        Locker locker(mutex);
        Base::push_back(tp);
    }
};

#endif // SV_HPP

联系方式

如果有BUG请联系 3111424384@qq.com,欢迎批评指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值