上一篇介绍了参数加载类, 所有的参数通过GET_PARAM获取, 根据提供的默认参数类型,采用模板自动识别返回相应类型。
不是所有的参数都会记录在册,所以方便管理,我现在需要把程序中使用到的参数全部输出,为了实现自动化管理的目的,目前可以想到的有两种方案:
方案一: 每次调用GET_PARAM进行登记,运行程序输出所有使用过的参数,显然这种方案并不可取,并不是所有的分支都能跑到,所以输出的参数列表也是不完整的。
方案二:使用模板静态变量使用即实例化的原则, 每一次调用GET_PARAM都定义一个结构体,然后使用该结构体初始化模板静态变量,初始化时需要构建链表,目前在linux下基于C++17标准测试通过,但windows下还无法完成。
需要涉及以下C++特性:
- 1、局部结构体用作模板参数;
- 2、局部结构体在不同的结构中,gcc编译器会定义出不同的结构名称;
- 3、模板类中可以访问局部结构体;
- 4、模板类静态变量,编译器对使用过的模板静态变量进行实例化
- 5、静态变量实例化时,必须对将对于类通过链表关联起来
局部结构体定义:
#define COMBINESTRUCTNAME1(section, key) section##key
#define COMBINESTRUCTNAME2(section, key) COMBINESTRUCTNAME1(section, key)
#define COMBINESTRUCTNAME(section, key) COMBINESTRUCTNAME2(section, key)
#define GET_PARAM(section, key, defVal) ([](){ struct COMBINESTRUCTNAME(PARAMTER_ , __LINE__) { \
static const char* getSection() { return #section; }\
static const char* getKey() { return #key; }\
static const char* getVal() { return #defVal; }\
};\
CParamterContainer<COMBINESTRUCTNAME(PARAMTER_ , __LINE__)>::GetInstance(); \
return CAppConfigAgent::get_instance().GetParam(section, key, defVal); \
})();
模板类定义
class ParamContainerBase
{
public:
//存储容器节点,返回容器头节点
static ParamContainerBase*& Head()
{
static ParamContainerBase *containerHead = 0;
return containerHead;
}
static void Initialize()
{
//初始化容器
ParamContainerBase* currContainer = Head();
while (currContainer != NULL)
{
CParamterMgr::get_instance().AddParam(currContainer->m_section, currContainer->m_key, currContainer->m_defVal);
currContainer = currContainer->m_nextContainer;
}
}
virtual void DoNothing()const
{
}
protected:
ParamContainerBase* m_nextContainer = nullptr;
const char* m_section;
const char* m_key;
const char* m_defVal;
};
//容器类
template<typename T>
class CParamterContainer : public ParamContainerBase
{
public:
constexpr CParamterContainer()
{
std::cout << "构建对象" << std::endl;
}
static CParamterContainer* GetInstance()
{
static CParamterContainer<T> containerIns;
return &containerIns;
}
//该函数为虚函数,编译器会进行检查,从而实现对静态变量引用的目的
virtual void DoNothing()const
{
m_param.DoNothing();
}
private:
struct ContaintInstance
{
ContaintInstance()
{
//静态变量初始化时,构建链表
std::cout << "初始化容器函数:" << typeid(T).name() << std::endl;
CParamterContainer *container = CParamterContainer::GetInstance();
container->m_nextContainer = Head();
container->m_section = T::getSection();
container->m_key = T::getKey();
container->m_defVal = T::getVal();
Head() = container;
}
inline void DoNothing()const {}
};
static ContaintInstance m_param;
};
template<typename T>
typename CParamterContainer<T>::ContaintInstance CParamterContainer<T>::m_param;
测试代码:
void test()
{
GET_PARAM("System", "LogLevel", 1000); GET_PARAM("System", "Delay", 5);
}
void test2()
{
GET_PARAM("System", "Cycle", 15);
}
class A{
public:
void test()
{
auto num = GET_PARAM("System", "threadNum", 15); auto dl = GET_PARAM("System", "Delay", 5);
std::cout << "threadNum:" << num << " Delay:" << dl << std::endl;
auto msg = GET_PARAM("System", "INFO", "Message");
std::cout << "INFO:" << msg << std::endl;
}
};
int main()
{
std::cout << "开始" << std::endl;
ParamContainerBase::Initialize();
std::map<std::string, std::map<std::string, std::string>> cfg;
cfg["System"]["threadNum"] = "2";
cfg["System"]["Delay"] = "12";
CAppConfigAgent::get_instance().AddConfigItem(cfg);
CParamterMgr::get_instance().Dump();
A().test();
return 0;
}
输出:
来源:oschina
链接:https://my.oschina.net/u/3312209/blog/4312610