如何实现可直接声明的带固定初始化的模板类变体?
问题描述
开发多类编码器,核心差异在于初始化类时使用的数据结构不同。现有代码如下,希望通过rdTagEncode myEncode;的简洁形式在其他代码中声明编码器,但无法找到正确语法。
头文件代码
struct tagTypeInfo { uint16_t start; uint16_t last; uint16_t count; std::string name; rdwrT rdwr; }; template <typename T> class encodedTag { public: encodedTag(vector<tagTypeInfo> tagInfo_) : tagInfo(tagInfo_) { int start = 0; for(auto & tag : tagInfo) { tag.start = start; tag.last = start + tag.count - 1; start = start + tag.count; } } uint16_t encode(uint16_t tag, T tagType) { assert(tag<tagInfo[tagType].count); return( tagInfo[tagType].start + tag ); } std::tuple<uint16_t, T> decode(uint16_t encodedTag) { int type = 0; uint16_t tag; // simple linear search as there are only a few entries for (auto it = begin(tagInfo); it != end(tagInfo); it++) { if (encodedTag >= it->start && encodedTag < it->last ) { // tag is in the range return {encodedTag - it->start , (T)type}; } type++; } assert(false); return {0,(T)0}; } std::string getName(T tagType) {return(tagInfo[tagType].name);} rdwrT getRdwr(T tagType) {return(tagInfo[tagType].rdwr);} private: std::vector<tagTypeInfo> tagInfo; }; extern std::vector<tagTypeInfo> rdTag; extern std::vector<tagTypeInfo> wrTag; //using rdTagEncode = encodedTag<rdTagT>(rdTag) <-- error
cpp文件代码
std::vector<tagTypeInfo> rdTag { {0, 0, NUM_HOSTRDTAG, "HostRdTag", RDWR_RD}, {0, 0, NUM_SYSRDTAG, "SysRdTag", RDWR_RD}, {0, 0, NUM_GCRDTAG, "GCRdTag", RDWR_RD} }; std::vector<tagTypeInfo> wrTag { {0, 0, NUM_HOSTWRTAG, "HostWrTag", RDWR_WR}, {0, 0, NUM_SYSWRTAG, "SysWrTag", RDWR_WR}, {0, 0, NUM_GCWRTAG, "GCWrTag", RDWR_WR} };
解决方案
using关键字仅用于定义类型别名,无法直接绑定类实例化时的构造参数,因此原写法不成立。以下两种方法可实现你的需求:
方法1:全局实例直接调用
步骤1:头文件声明全局实例
在头文件末尾添加:
extern encodedTag<rdTagT> rdTagEncoder;
步骤2:cpp文件初始化实例
在cpp文件末尾添加:
encodedTag<rdTagT> rdTagEncoder(rdTag);
使用方式
其他代码中无需声明新对象,直接调用全局实例即可:
// 编码示例 uint16_t encoded = rdTagEncoder.encode(0, rdTagT::Host); // 解码示例 auto [tag, type] = rdTagEncoder.decode(encoded);
方法2:模板绑定数据结构,实现类别名声明
通过修改模板类,将数据结构的指针作为模板参数,从而用using定义绑定了特定数据的类型别名。
步骤1:修改模板类定义
template <typename T, const std::vector<tagTypeInfo>* TagInfoPtr> class encodedTag { public: encodedTag() : tagInfo(*TagInfoPtr) { int start = 0; for(auto & tag : tagInfo) { tag.start = start; tag.last = start + tag.count - 1; start = start + tag.count; } } // 其余成员函数与原代码一致... private: std::vector<tagTypeInfo> tagInfo; };
步骤2:头文件定义类型别名
extern std::vector<tagTypeInfo> rdTag; // 定义绑定rdTag的类型别名 using rdTagEncode = encodedTag<rdTagT, &rdTag>;
使用方式
现在可以通过简洁的声明创建对象:
rdTagEncode myEncode; // 调用示例 uint16_t encoded = myEncode.encode(1, rdTagT::Sys);
额外修复提示
原decode函数的判断条件存在逻辑漏洞:encodedTag < it->last会漏掉等于last的合法标签,应修改为:
if (encodedTag >= it->start && encodedTag <= it->last )
内容的提问来源于stack exchange,提问作者Andy Tomlin
相关产品推荐
相关产品推荐

