C++自定义pair类如何实现直接通过[]运算符访问输出内部元素
我实现了一个功能类似std::pair的自定义bpair结构体,初始实现代码如下:
template<typename firstType,typename secondType> struct bpair{ firstType first; secondType second; bpair(firstType firstNew,secondType secondNew) { first = firstNew; second = secondNew; } variant<firstType,secondType> operator[](size_t index) { if(index == 0) { return first; } return second; } };
现有测试调用代码:
bpair<string,int> hey = bpair(string("hi"),34); cout << get<string>(hey[0]);
目前[]运算符返回variant类型,必须通过get模板函数取出值才能正常输出,想要实现直接通过[]访问元素,支持如下调用写法:
cout << hey[0];
首先明确核心限制:C++中函数返回值类型必须在编译阶段确定,如果传入[]的索引是运行时才能确定值的变量(比如随机生成的0/1),没有办法在编译期预知返回的是firstType还是secondType,这种场景下返回variant是合理的实现方式。要实现直接输出hey[0],有两种可选方案,优先选改动最小的方案1即可。
方案1:重载variant的流输出运算符(兼容运行时索引,改动最小)
不需要修改现有bpair的结构体逻辑,只要在全局或者bpair所在命名空间添加variant的流输出重载,内部通过std::visit自动匹配当前存储值的类型完成输出:
#include <variant> #include <ostream> template<typename T1, typename T2> std::ostream& operator<<(std::ostream& os, const std::variant<T1, T2>& v) { std::visit([&os](const auto& val) { os << val; }, v); return os; }
添加这段代码后,不管索引是编译期写死的0/1字面量,还是运行时动态计算的索引值,都可以直接通过cout << hey[0]的写法输出内容,不需要手动调用get。
方案2:编译期常量索引重载(零开销返回元素引用)
如果所有访问场景的索引都是写死的0、1常量,不需要动态传索引,可以在C++23及以上标准中新增模板化的[]运算符重载,编译期直接返回对应元素的引用,没有variant的额外开销:
#include <utility> #include <variant> template<typename firstType,typename secondType> struct bpair{ firstType first; secondType second; // 改用初始化列表提升构造效率 bpair(firstType firstNew,secondType secondNew): first(std::move(firstNew)), second(std::move(secondNew)) {} // C++23及以上支持模板化operator[] template<size_t Index> auto& operator[](std::integral_constant<size_t, Index>) { if constexpr (Index == 0) { return first; } else if constexpr (Index == 1) { return second; } else { static_assert(Index < 2, "bpair index out of bounds"); } } // 保留原有运行时索引逻辑 std::variant<firstType,secondType> operator[](size_t index) { if(index == 0) { return first; } return second; } };
注意这个方案如果要走编译期返回引用的逻辑,调用时需要传入编译期常量作为参数,写法为hey[std::integral_constant<size_t, 0>{}],直接写hey[0]会优先匹配原有运行时索引的重载,还是需要配合方案1的流重载才能直接输出,因此日常使用优先选方案1即可。
内容的提问来源于stack exchange,提问作者Bfyuvf

