C++ 九阴真经之编译期汇总

爷,独闯天下 提交于 2020-08-06 09:54:40

    上一篇介绍了参数加载类, 所有的参数通过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;
}

输出:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!