C++反射機(jī)制:可變參數(shù)模板實現(xiàn)C++反射

1. 概要

??本文描述一個通過C++可變參數(shù)模板實現(xiàn)C++反射機(jī)制的方法蝙场。該方法非常實用,在Nebula高性能網(wǎng)絡(luò)框架中大量應(yīng)用粱年,實現(xiàn)了非常強(qiáng)大的動態(tài)加載動態(tài)創(chuàng)建功能售滤。

??C++11的新特性--可變模版參數(shù)(variadic templates)是C++11新增的最強(qiáng)大的特性之一,它對參數(shù)進(jìn)行了高度泛化台诗,它能表示0到任意個數(shù)完箩、任意類型的參數(shù)。關(guān)于可變參數(shù)模板的原理和應(yīng)用不是本文重點(diǎn)拉队,不過通過本文中的例子也可充分了解可變參數(shù)模板是如何應(yīng)用的弊知。

??熟悉Java或C#的同學(xué)應(yīng)該都知道反射機(jī)制,很多有名的框架都用到了反射這種特性粱快,簡單的理解就是只根據(jù)類的名字(字符串)創(chuàng)建類的實例秩彤。 C++并沒有直接從語言上提供反射機(jī)制給我們用叔扼,不過無所不能的C++可以通過一些trick來實現(xiàn)反射。Bwar也是在開發(fā)Nebula框架的時候需要用到反射機(jī)制漫雷,在網(wǎng)上參考了一些資料結(jié)合自己對C++11可變參數(shù)模板的理解實現(xiàn)了C++反射瓜富。

2. C++11之前的模擬反射機(jī)制實現(xiàn)

??Nebula框架是一個高性能事件驅(qū)動通用網(wǎng)絡(luò)框架,框架本身無任何業(yè)務(wù)邏輯實現(xiàn)降盹,卻為快速實現(xiàn)業(yè)務(wù)提供了強(qiáng)大的功能与柑、統(tǒng)一的接口。業(yè)務(wù)邏輯通過從Nebula的Actor類接口編譯成so動態(tài)庫蓄坏,Nebula加載業(yè)務(wù)邏輯動態(tài)庫實現(xiàn)各種功能Server价捧,開發(fā)人員只需專注于業(yè)務(wù)邏輯代碼編寫,網(wǎng)絡(luò)通信涡戳、定時器结蟋、數(shù)據(jù)序列化反序列化、采用何種通信協(xié)議等全部交由框架完成渔彰。

??開發(fā)人員編寫的業(yè)務(wù)邏輯類從Nebula的基類派生椎眯,但各業(yè)務(wù)邏輯派生類對Nebula來說是完全未知的,Nebula需要加載這些動態(tài)庫并創(chuàng)建動態(tài)庫中的類實例就需要用到反射機(jī)制胳岂。第一版的Nebula及其前身Starship框架以C++03標(biāo)準(zhǔn)開發(fā),未知類名舔稀、未知參數(shù)個數(shù)乳丰、未知參數(shù)類型、更未知實參的情況下内贮,Bwar沒想到一個有效的加載動態(tài)庫并創(chuàng)建類實例的方式产园。為此,將所有業(yè)務(wù)邏輯入口類的構(gòu)造函數(shù)都設(shè)計成無參構(gòu)造函數(shù)夜郁。

??Bwar在2015年未找到比較好的實現(xiàn)什燕,自己想了一種較為取巧的加載動態(tài)庫并創(chuàng)建類實例的方法(這還不是反射機(jī)制,只是實現(xiàn)了可以或需要反射機(jī)制來實現(xiàn)的功能)竞端。這個方法在Nebula的C++03版本中應(yīng)用并實測通過屎即,同時也是在一個穩(wěn)定運(yùn)行兩年多的IM底層框架Starship中應(yīng)用。下面給出這種實現(xiàn)方法的代碼:

CmdHello.hpp:

#ifdef __cplusplus

extern "C" {

#endif

// @brief 創(chuàng)建函數(shù)聲明

// @note 插件代碼編譯成so后存放到plugin目錄事富,框架加載動態(tài)庫后調(diào)用create()創(chuàng)建插件類實例技俐。

neb::Cmd* create();

#ifdef __cplusplus

}

#endif

namespace im

{

class CmdHello: public neb::Cmd

{

public:

? ? CmdHello();

? ? virtual ~CmdHello();

? ? virtual bool AnyMessage();

};

} /* namespace im */

CmdHello.cpp:

#include "CmdHello.hpp"

#ifdef __cplusplus

extern "C" {

#endif

neb::Cmd* create()

{

? ? neb::Cmd* pCmd = new im::CmdHello();

? ? return(pCmd);

}

#ifdef __cplusplus

}

#endif

namespace im

{

CmdHello::CmdHello()

{

}

CmdHello::~CmdHello()

{

}

bool CmdHello::AnyMessage()

{

? ? std::cout << "CmdHello" << std::endl;

? ? return(true);

}

}

??實現(xiàn)的關(guān)鍵在于create()函數(shù),雖然每個動態(tài)庫都寫了create()函數(shù)统台,但動態(tài)庫加載時每個create()函數(shù)的地址是不一樣的雕擂,通過不同地址調(diào)用到的函數(shù)也就是不一樣的,所以可以創(chuàng)建不同的實例贱勃。下面給出動態(tài)庫加載和調(diào)用create()函數(shù)井赌,創(chuàng)建類實例的代碼片段:

void* pHandle = NULL;

? ? pHandle = dlopen(strSoPath.c_str(), RTLD_NOW);

? ? char* dlsym_error = dlerror();

? ? if (dlsym_error)

? ? {

? ? ? ? LOG4_FATAL("cannot load dynamic lib %s!" , dlsym_error);

? ? ? ? if (pHandle != NULL)

? ? ? ? {

? ? ? ? ? ? dlclose(pHandle);

? ? ? ? }

? ? ? ? return(pSo);

? ? }

? ? CreateCmd* pCreateCmd = (CreateCmd*)dlsym(pHandle, strSymbol.c_str());

? ? dlsym_error = dlerror();

? ? if (dlsym_error)

? ? {

? ? ? ? LOG4_FATAL("dlsym error %s!" , dlsym_error);

? ? ? ? dlclose(pHandle);

? ? ? ? return(pSo);

? ? }

? ? Cmd* pCmd = pCreateCmd();

??對應(yīng)這動態(tài)庫加載代碼片段的配置文件如下:

{"cmd":10001, "so_path":"plugins/CmdHello.so", "entrance_symbol":"create", "load":false, "version":1}

??這些代碼實現(xiàn)達(dá)到了加載動態(tài)庫并創(chuàng)建框架未知類實例的目的谤逼。不過沒有反射機(jī)制那么靈活,用起來也稍顯麻煩仇穗,開發(fā)人員寫好業(yè)務(wù)邏輯類之后還需要實現(xiàn)一個對應(yīng)的全局create()函數(shù)流部。

3. C++反射機(jī)制實現(xiàn)思考

??Bwar曾經(jīng)用C++模板封裝過一個基于pthread的通用線程類。下面是這個線程模板類具有代表性的一個函數(shù)實現(xiàn)仪缸,對設(shè)計C++反射機(jī)制實現(xiàn)有一定的啟發(fā):

template <typename T>

void CThread<T>::StartRoutine(void* para)

{

? ? T* pT;

? ? pT = (T*) para;

? ? pT->Run();

}

??與之相似贵涵,創(chuàng)建一個未知的類實例可以通過new T()的方式來實現(xiàn),如果是帶參數(shù)的構(gòu)造函數(shù)恰画,則可以new T(T1, T2)來實現(xiàn)宾茂。那么,通過類名創(chuàng)建類實例拴还,建立"ClassName"與T的對應(yīng)關(guān)系跨晴,或者建立"ClassName"與包含了new T()語句的函數(shù)的對應(yīng)關(guān)系即可實現(xiàn)無參構(gòu)造類的反射機(jī)制∑郑考慮到new T(T1, T2)的參數(shù)個數(shù)和參數(shù)類型都未知端盆,應(yīng)用C++11的可變參數(shù)模板解決參數(shù)問題,即完成帶參構(gòu)造類的反射機(jī)制费封。

4. Nebula網(wǎng)絡(luò)框架中的C++反射機(jī)制實現(xiàn)

??研究C++反射機(jī)制實現(xiàn)最重要是Nebula網(wǎng)絡(luò)框架中有極其重要的應(yīng)用焕妙,而Nebula框架在實現(xiàn)并應(yīng)用了反射機(jī)制之后代碼量精簡了10%左右,同時易用性也有了很大的提高弓摘,再考慮到應(yīng)用反射機(jī)制后給基于Nebula的業(yè)務(wù)邏輯開發(fā)帶來的好處焚鹊,可以說反射機(jī)制是Nebula框架僅次于以C++14標(biāo)準(zhǔn)重寫的重大提升。

??Nebula的Actor為事件(消息)處理者韧献,所有業(yè)務(wù)邏輯均抽象成事件和事件處理末患,反射機(jī)制正是應(yīng)用在Actor的動態(tài)創(chuàng)建上。Actor分為Cmd锤窑、Module璧针、Step、Session四種不同類型渊啰。業(yè)務(wù)邏輯代碼均通過從這四種不同類型時間處理者派生子類來實現(xiàn)探橱,專注于業(yè)務(wù)邏輯實現(xiàn),而無須關(guān)注業(yè)務(wù)邏輯之外的內(nèi)容虽抄。Cmd和Module都是消息處理入庫走搁,業(yè)務(wù)開發(fā)人員定義了什么樣的Cmd和Module對框架而言是未知的,因此這些Cmd和Module都配置在配置文件里迈窟,Nebula通過配置文件中的Cmd和Module的名稱(字符串)完成它們的實例創(chuàng)建私植。通過反射機(jī)制動態(tài)創(chuàng)建Actor的關(guān)鍵代碼如下:

Actor類:

class Actor: public std::enable_shared_from_this<Actor>

Actor創(chuàng)建工廠(注意看代碼注釋):

template<typename ...Targs>

class ActorFactory

{

public:

? ? static ActorFactory* Instance()

? ? {

? ? ? ? if (nullptr == m_pActorFactory)

? ? ? ? {

? ? ? ? ? ? m_pActorFactory = new ActorFactory();

? ? ? ? }

? ? ? ? return(m_pActorFactory);

? ? }

? ? virtual ~ActorFactory(){};

? ? // 將“實例創(chuàng)建方法(DynamicCreator的CreateObject方法)”注冊到ActorFactory,注冊的同時賦予這個方法一個名字“類名”车酣,后續(xù)可以通過“類名”獲得該類的“實例創(chuàng)建方法”曲稼。這個實例創(chuàng)建方法實質(zhì)上是個函數(shù)指針索绪,在C++11里std::function的可讀性比函數(shù)指針更好,所以用了std::function贫悄。

? ? bool Regist(const std::string& strTypeName, std::function<Actor*(Targs&&... args)> pFunc);

? ? // 傳入“類名”和參數(shù)創(chuàng)建類實例瑞驱,方法內(nèi)部通過“類名”從m_mapCreateFunction獲得了對應(yīng)的“實例創(chuàng)建方法(DynamicCreator的CreateObject方法)”完成實例創(chuàng)建操作。

? ? Actor* Create(const std::string& strTypeName, Targs&&... args);

private:

? ? ActorFactory(){};

? ? static ActorFactory<Targs...>* m_pActorFactory;

? ? std::unordered_map<std::string, std::function<Actor*(Targs&&...)> > m_mapCreateFunction;

};

template<typename ...Targs>

ActorFactory<Targs...>* ActorFactory<Targs...>::m_pActorFactory = nullptr;

template<typename ...Targs>

bool ActorFactory<Targs...>::Regist(const std::string& strTypeName, std::function<Actor*(Targs&&... args)> pFunc)

{

? ? if (nullptr == pFunc)

? ? {

? ? ? ? return (false);

? ? }

? ? bool bReg = m_mapCreateFunction.insert(

? ? ? ? ? ? ? ? ? ? std::make_pair(strTypeName, pFunc)).second;

? ? return (bReg);

}

template<typename ...Targs>

Actor* ActorFactory<Targs...>::Create(const std::string& strTypeName, Targs&&... args)

{

? ? auto iter = m_mapCreateFunction.find(strTypeName);

? ? if (iter == m_mapCreateFunction.end())

? ? {

? ? ? ? return (nullptr);

? ? }

? ? else

? ? {

? ? ? ? return (iter->second(std::forward<Targs>(args)...));

? ? }

}

動態(tài)創(chuàng)建類(注意看代碼注釋):

template<typename T, typename...Targs>

class DynamicCreator

{

public:

? ? struct Register

? ? {

? ? ? ? Register()

? ? ? ? {

? ? ? ? ? ? char* szDemangleName = nullptr;

? ? ? ? ? ? std::string strTypeName;

#ifdef __GNUC__

? ? ? ? ? ? szDemangleName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);

#else

? ? ? ? ? ? // 注意:這里不同編譯器typeid(T).name()返回的字符串不一樣窄坦,需要針對編譯器寫對應(yīng)的實現(xiàn)

? ? ? ? ? ? //in this format?:? ? szDemangleName =? typeid(T).name();

? ? ? ? ? ? szDemangleName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);

#endif

? ? ? ? ? ? if (nullptr != szDemangleName)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? strTypeName = szDemangleName;

? ? ? ? ? ? ? ? free(szDemangleName);

? ? ? ? ? ? }

? ? ? ? ? ? ActorFactory<Targs...>::Instance()->Regist(strTypeName, CreateObject);

? ? ? ? }

? ? ? ? inline void do_nothing()const { };

? ? };

? ? DynamicCreator()

? ? {

? ? ? ? m_oRegister.do_nothing();? // 這里的函數(shù)調(diào)用雖無實際內(nèi)容唤反,卻是在調(diào)用動態(tài)創(chuàng)建函數(shù)前完成m_oRegister實例創(chuàng)建的關(guān)鍵

? ? }

? ? virtual ~DynamicCreator(){};

? ? // 動態(tài)創(chuàng)建實例的方法,所有Actor實例均通過此方法創(chuàng)建鸭津。這是個模板方法彤侍,實際上每個Actor的派生類都對應(yīng)了自己的CreateObject方法挥转。

? ? static T* CreateObject(Targs&&... args)

? ? {

? ? ? ? T* pT = nullptr;

? ? ? ? try

? ? ? ? {

? ? ? ? ? ? pT = new T(std::forward<Targs>(args)...);

? ? ? ? }

? ? ? ? catch(std::bad_alloc& e)

? ? ? ? {

? ? ? ? ? ? return(nullptr);

? ? ? ? }

? ? ? ? return(pT);

? ? }

private:

? ? static Register m_oRegister;

};

template<typename T, typename ...Targs>

typename DynamicCreator<T, Targs...>::Register DynamicCreator<T, Targs...>::m_oRegister;

??上面ActorFactory和DynamicCreator就是C++反射機(jī)制的全部實現(xiàn)食拜。要完成實例的動態(tài)創(chuàng)建還需要類定義必須滿足(模板)要求。下面看一個可以動態(tài)創(chuàng)建實例的CmdHello<a name="CmdHello"></a>類定義(注意看代碼注釋):

// 類定義需要使用多重繼承绪氛。

// 第一重繼承neb::Cmd是CmdHello的實際基類(neb::Cmd為Actor的派生類闻书,Actor是什么在本節(jié)開始的描述中有說明)名斟;

// 第二重繼承為通過類名動態(tài)創(chuàng)建實例的需要,與template<typename T, typename...Targs> class DynamicCreator定義對應(yīng)著看就很容易明白第一個模板參數(shù)(CmdHello)為待動態(tài)創(chuàng)建的類名魄眉,其他參數(shù)為該類的構(gòu)造函數(shù)參數(shù)砰盐。

// 如果參數(shù)為某個類型的引用,作為模板參數(shù)時應(yīng)指定到類型坑律。比如: 參數(shù)類型const std::string&只需在neb::DynamicCreator的模板參數(shù)里填std::string

// 如果參數(shù)為某個類型的指針楞卡,作為模板參數(shù)時需指定為類型的指針。比如:參數(shù)類型const std::string*則需在neb::DynamicCreator的模板參數(shù)里填std::string*

class CmdHello: public neb::Cmd, public neb::DynamicCreator<CmdHello, int32>

{

public:

? ? CmdHello(int32 iCmd);

? ? virtual ~CmdHello();

? ? virtual bool Init();

? ? virtual bool AnyMessage(

? ? ? ? ? ? ? ? ? ? std::shared_ptr<neb::SocketChannel> pChannel,

? ? ? ? ? ? ? ? ? ? const MsgHead& oMsgHead,

? ? ? ? ? ? ? ? ? ? const MsgBody& oMsgBody);

};

??再看看上面的反射機(jī)制是怎么調(diào)用的:

template <typename ...Targs>

std::shared_ptr<Cmd> WorkerImpl::MakeSharedCmd(Actor* pCreator, const std::string& strCmdName, Targs... args)

{

? ? LOG4_TRACE("%s(CmdName \"%s\")", __FUNCTION__, strCmdName.c_str());

? ? Cmd* pCmd = dynamic_cast<Cmd*>(ActorFactory<Targs...>::Instance()->Create(strCmdName, std::forward<Targs>(args)...));

? ? if (nullptr == pCmd)

? ? {

? ? ? ? LOG4_ERROR("failed to make shared cmd \"%s\"", strCmdName.c_str());

? ? ? ? return(nullptr);

? ? }

? ? ...

}

??MakeSharedCmd()方法的調(diào)用:

MakeSharedCmd(nullptr, oCmdConf["cmd"][i]("class"), iCmd);

??至此通過C++可變參數(shù)模板實現(xiàn)C++反射機(jī)制實現(xiàn)已全部講完脾歇,相信讀到這里已經(jīng)有了一定的理解,這是Nebula框架的核心功能之一淘捡,已有不少基于Nebula的應(yīng)用實踐藕各,是可用于生產(chǎn)的C++反射實現(xiàn)。

??這個C++反射機(jī)制的應(yīng)用容易出錯的地方是

類定義class CmdHello: public neb::Cmd, public neb::DynamicCreator<CmdHello, int32>中的模板參數(shù)一定要與構(gòu)造函數(shù)中的參數(shù)類型嚴(yán)格匹配(不明白的請再閱讀一遍CmdHello類定義)焦除。

調(diào)用創(chuàng)建方法的地方傳入的實參類型必須與形參類型嚴(yán)格匹配激况。不能有隱式的類型轉(zhuǎn)換,比如類構(gòu)造函數(shù)的形參類型為unsigned int膘魄,調(diào)用ActorFactory<Targs...>::Instance()->Create()時傳入的實參為int或short或unsigned short或enum都會導(dǎo)致ActorFactory無法找到對應(yīng)的“實例創(chuàng)建方法”乌逐,從而導(dǎo)致不能通過類名正常創(chuàng)建實例。

??注意以上兩點(diǎn)创葡,基本就不會有什么問題了浙踢。

5. 一個可執(zhí)行的例子

??上面為了說明C++反射機(jī)制給出的代碼全都來自Nebula框架。最后再提供一個可執(zhí)行的例子加深理解灿渴。

DynamicCreate.cpp:

#include <string>

#include <iostream>

#include <typeinfo>

#include <memory>

#include <unordered_map>

#include <cxxabi.h>

namespace neb

{

class Actor

{

public:

? ? Actor(){std::cout << "Actor construct" << std::endl;}

? ? virtual ~Actor(){};

? ? virtual void Say()

? ? {

? ? ? ? std::cout << "Actor" << std::endl;

? ? }

};

template<typename ...Targs>

class ActorFactory

{

public:

? ? //typedef Actor* (*ActorCreateFunction)();

? ? //std::function< Actor*(Targs...args) > pp;

? ? static ActorFactory* Instance()

? ? {

? ? ? ? std::cout << "static ActorFactory* Instance()" << std::endl;

? ? ? ? if (nullptr == m_pActorFactory)

? ? ? ? {

? ? ? ? ? ? m_pActorFactory = new ActorFactory();

? ? ? ? }

? ? ? ? return(m_pActorFactory);

? ? }

? ? virtual ~ActorFactory(){};

? ? //Lambda: static std::string ReadTypeName(const char * name)

? ? //bool Regist(const std::string& strTypeName, ActorCreateFunction pFunc)

? ? //bool Regist(const std::string& strTypeName, std::function<Actor*()> pFunc)

? ? bool Regist(const std::string& strTypeName, std::function<Actor*(Targs&&... args)> pFunc)

? ? {

? ? ? ? std::cout << "bool ActorFactory::Regist(const std::string& strTypeName, std::function<Actor*(Targs... args)> pFunc)" << std::endl;

? ? ? ? if (nullptr == pFunc)

? ? ? ? {

? ? ? ? ? ? return(false);

? ? ? ? }

? ? ? ? std::string strRealTypeName = strTypeName;

? ? ? ? //[&strTypeName, &strRealTypeName]{int iPos = strTypeName.rfind(' '); strRealTypeName = std::move(strTypeName.substr(iPos+1, strTypeName.length() - (iPos + 1)));};

? ? ? ? bool bReg = m_mapCreateFunction.insert(std::make_pair(strRealTypeName, pFunc)).second;

? ? ? ? std::cout << "m_mapCreateFunction.size() =" << m_mapCreateFunction.size() << std::endl;

? ? ? ? return(bReg);

? ? }

? ? Actor* Create(const std::string& strTypeName, Targs&&... args)

? ? {

? ? ? ? std::cout << "Actor* ActorFactory::Create(const std::string& strTypeName, Targs... args)" << std::endl;

? ? ? ? auto iter = m_mapCreateFunction.find(strTypeName);

? ? ? ? if (iter == m_mapCreateFunction.end())

? ? ? ? {

? ? ? ? ? ? return(nullptr);

? ? ? ? }

? ? ? ? else

? ? ? ? {

? ? ? ? ? ? //return(iter->second());

? ? ? ? ? ? return(iter->second(std::forward<Targs>(args)...));

? ? ? ? }

? ? }

private:

? ? ActorFactory(){std::cout << "ActorFactory construct" << std::endl;};

? ? static ActorFactory<Targs...>* m_pActorFactory;?

? ? std::unordered_map<std::string, std::function<Actor*(Targs&&...)> > m_mapCreateFunction;

};

template<typename ...Targs>

ActorFactory<Targs...>* ActorFactory<Targs...>::m_pActorFactory = nullptr;

template<typename T, typename ...Targs>

class DynamicCreator

{

public:

? ? struct Register

? ? {

? ? ? ? Register()

? ? ? ? {

? ? ? ? ? ? std::cout << "DynamicCreator.Register construct" << std::endl;

? ? ? ? ? ? char* szDemangleName = nullptr;

? ? ? ? ? ? std::string strTypeName;

#ifdef __GNUC__

? ? ? ? ? ? szDemangleName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);

#else

? ? ? ? ? ? //in this format?:? ? szDemangleName =? typeid(T).name();

? ? ? ? ? ? szDemangleName = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr);

#endif

? ? ? ? ? ? if (nullptr != szDemangleName)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? strTypeName = szDemangleName;

? ? ? ? ? ? ? ? free(szDemangleName);

? ? ? ? ? ? }

? ? ? ? ? ? ActorFactory<Targs...>::Instance()->Regist(strTypeName, CreateObject);

? ? ? ? }

? ? ? ? inline void do_nothing()const { };

? ? };

? ? DynamicCreator()

? ? {

? ? ? ? std::cout << "DynamicCreator construct" << std::endl;

? ? ? ? m_oRegister.do_nothing();

? ? }

? ? virtual ~DynamicCreator(){m_oRegister.do_nothing();};

? ? static T* CreateObject(Targs&&... args)

? ? {

? ? ? ? std::cout << "static Actor* DynamicCreator::CreateObject(Targs... args)" << std::endl;

? ? ? ? return new T(std::forward<Targs>(args)...);

? ? }

? ? virtual void Say()

? ? {

? ? ? ? std::cout << "DynamicCreator say" << std::endl;

? ? }

? ? static Register m_oRegister;

};

template<typename T, typename ...Targs>

typename DynamicCreator<T, Targs...>::Register DynamicCreator<T, Targs...>::m_oRegister;

class Cmd: public Actor, public DynamicCreator<Cmd>

{

public:

? ? Cmd(){std::cout << "Create Cmd " << std::endl;}

? ? virtual void Say()

? ? {

? ? ? ? std::cout << "I am Cmd" << std::endl;

? ? }

};

class Step: public Actor, DynamicCreator<Step, std::string, int>

{

public:

? ? Step(const std::string& strType, int iSeq){std::cout << "Create Step " << strType << " with seq " << iSeq << std::endl;}

? ? virtual void Say()

? ? {

? ? ? ? std::cout << "I am Step" << std::endl;

? ? }

};

class Worker

{

public:

? ? template<typename ...Targs>

? ? Actor* CreateActor(const std::string& strTypeName, Targs&&... args)

? ? {

? ? ? ? Actor* p = ActorFactory<Targs...>::Instance()->Create(strTypeName, std::forward<Targs>(args)...);

? ? ? ? return(p);

? ? }

};

}

int main()

{

? ? //Actor* p1 = ActorFactory<std::string, int>::Instance()->Create(std::string("Cmd"), std::string("neb::Cmd"), 1001);

? ? //Actor* p3 = ActorFactory<>::Instance()->Create(std::string("Cmd"));

? ? neb::Worker W;

? ? neb::Actor* p1 = W.CreateActor(std::string("neb::Cmd"));

? ? p1->Say();

? ? //std::cout << abi::__cxa_demangle(typeid(Worker).name(), nullptr, nullptr, nullptr) << std::endl;

? ? std::cout << "----------------------------------------------------------------------" << std::endl;

? ? neb::Actor* p2 = W.CreateActor(std::string("neb::Step"), std::string("neb::Step"), 1002);

? ? p2->Say();

? ? return(0);

}

??Nebula框架是用C++14標(biāo)準(zhǔn)寫的洛波,在Makefile中有預(yù)編譯選項胰舆,可以用C++11標(biāo)準(zhǔn)編譯,但未完全支持C++11全部標(biāo)準(zhǔn)的編譯器可能無法編譯成功蹬挤。實測g++ 4.8.5不支持可變參數(shù)模板缚窿,建議采用gcc 5.0以后的編譯器,最好用gcc 6焰扳,Nebula用的是gcc6.4倦零。

??這里給出的例子DynamicCreate.cpp可以這樣編譯:

g++ -std=c++11 DynamicCreate.cpp -o DynamicCreate

??程序執(zhí)行結(jié)果如下:

DynamicCreator.Register construct

static ActorFactory* Instance()

ActorFactory construct

bool ActorFactory::Regist(const std::string& strTypeName, std::function<Actor*(Targs... args)> pFunc)

m_mapCreateFunction.size() =1

DynamicCreator.Register construct

static ActorFactory* Instance()

ActorFactory construct

bool ActorFactory::Regist(const std::string& strTypeName, std::function<Actor*(Targs... args)> pFunc)

m_mapCreateFunction.size() =1

static ActorFactory* Instance()

Actor* ActorFactory::Create(const std::string& strTypeName, Targs... args)

static Actor* DynamicCreator::CreateObject(Targs... args)

Actor construct

DynamicCreator construct

Create Cmd

I am Cmd

----------------------------------------------------------------------

static ActorFactory* Instance()

Actor* ActorFactory::Create(const std::string& strTypeName, Targs... args)

static Actor* DynamicCreator::CreateObject(Targs... args)

Actor construct

DynamicCreator construct

Create Step neb::Step with seq 1002

I am Step

??深圳網(wǎng)站建設(shè)www.sz886.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吨悍,隨后出現(xiàn)的幾起案子扫茅,更是在濱河造成了極大的恐慌,老刑警劉巖畜份,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诞帐,死亡現(xiàn)場離奇詭異,居然都是意外死亡爆雹,警方通過查閱死者的電腦和手機(jī)停蕉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钙态,“玉大人慧起,你說我怎么就攤上這事〔岬梗” “怎么了蚓挤?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驻子。 經(jīng)常有香客問我灿意,道長,這世上最難降的妖魔是什么崇呵? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任缤剧,我火速辦了婚禮,結(jié)果婚禮上域慷,老公的妹妹穿的比我還像新娘荒辕。我一直安慰自己,他們只是感情好犹褒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布抵窒。 她就那樣靜靜地躺著,像睡著了一般叠骑。 火紅的嫁衣襯著肌膚如雪李皇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天宙枷,我揣著相機(jī)與錄音疙赠,去河邊找鬼付材。 笑死,一個胖子當(dāng)著我的面吹牛圃阳,可吹牛的內(nèi)容都是我干的厌衔。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼捍岳,長吁一口氣:“原來是場噩夢啊……” “哼富寿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锣夹,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤页徐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后银萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體变勇,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年贴唇,在試婚紗的時候發(fā)現(xiàn)自己被綠了搀绣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡戳气,死狀恐怖链患,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓶您,我是刑警寧澤麻捻,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站呀袱,受9級特大地震影響贸毕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜夜赵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一崖咨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧油吭,春花似錦、人聲如沸署拟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽推穷。三九已至心包,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馒铃,已是汗流浹背蟹腾。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工痕惋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娃殖。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓值戳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親炉爆。 傳聞我的和親對象是個殘疾皇子堕虹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容