如何使基结构体的每个using别名成为唯一类型,解决std::get按类型访问元组元素的冲突问题
如何使基结构体的每个using别名成为唯一类型,解决std::get按类型访问元组元素的冲突问题
嘿,我懂你碰到的这个坑——想用std::get<类型>直接抓取元组里的元素,结果因为TypeOne和TypeThree本质是同一个SomeType的实例化类型,编译器直接懵了,不知道该返回哪个对吧?
问题的核心很简单:TypeOne和TypeThree都是SomeType<std::string, int, double>的别名,它们的类型完全一致,而std::get<类型>要求元组里该类型只能出现一次,不然就会触发歧义。要解决这个问题,我们得给每个using出来的类型加个“专属标记”,让它们哪怕模板参数一样,也能被编译器当成不同的类型。
下面给你完善一下你提到的lambda标识思路,这是个很巧妙的解决方案:
首先,我们修改原有的结构体,给它加一个额外的标识类型参数,这个参数不需要任何实际功能,只是用来区分不同的类型实例:
#include <tuple> #include <string> // 带专属标识的结构体,ID参数用来做类型区分 template<typename ID, typename... Params> struct SomeTypeWithId { std::tuple<Params...> params; // 构造函数直接转发参数,用法和原来的SomeType一致 template<typename... Args> SomeTypeWithId(Args&&... args) : params(std::forward<Args>(args)...) {} };
接下来定义别名的时候,用不同的lambda表达式作为ID参数——C++里每个lambda的闭包类型都是独一无二的,哪怕两个lambda的代码完全一样,它们的类型也不相同,刚好可以用来做这个“专属标记”:
// 每个别名用独立的lambda作为ID,确保类型唯一 using TypeOne = SomeTypeWithId<decltype([](){}) , std::string, int, double>; using TypeTwo = SomeTypeWithId<decltype([](){}) , std::string, std::string, int>; using TypeThree = SomeTypeWithId<decltype([](){}) , std::string, int, double>;
现在TypeOne和TypeThree就变成了完全不同的类型,这时候再用std::get<类型>访问元组就完全没问题了:
int main() { std::tuple<TypeOne, TypeTwo, TypeThree> tuple{ TypeOne{"hello", 42, 3.14}, TypeTwo{"foo", "bar", 100}, TypeThree{"world", 99, 2.71} }; // 现在可以正常按类型访问,不会有歧义了 auto& first = std::get<TypeOne>(tuple); auto& second = std::get<TypeTwo>(tuple); auto& third = std::get<TypeThree>(tuple); return 0; }
如果你觉得lambda的方式可读性不够,也可以用自定义的空结构体作为标识,效果是一样的:
// 定义专属的空结构体作为标识 struct IdOne {}; struct IdThree {}; using TypeOne = SomeTypeWithId<IdOne, std::string, int, double>; using TypeThree = SomeTypeWithId<IdThree, std::string, int, double>;
这种方式更直观,适合需要明确标识类型的场景,看你个人习惯选就行。
备注:内容来源于stack exchange,提问作者Eshy
相关产品推荐
相关产品推荐

