重载operator[]时传入初始化列表出现调用歧义,如何解决?
解决operator[]重载的调用歧义问题
当你使用obj[{0}]调用时,编译器无法确定是将初始化列表{0}转换为std::vector<uint32_t>还是std::vector<std::vector<uint32_t>>(后者会被解释为包含一个std::vector<uint32_t>{0}元素的二维向量),因此出现歧义。以下是几种可行的解决方法:
1. 显式指定参数类型
直接在调用时明确构造目标类型,消除歧义:
obj[std::vector<uint32_t>{0}]; // 明确调用vector<uint32_t>版本 obj[std::vector<std::vector<uint32_t>>{{0}}]; // 明确调用二维vector版本
2. 添加initializer_list<uint32_t>重载
新增一个接受std::initializer_list<uint32_t>的重载,让单元素初始化列表优先匹配这个更直接的版本,再转发到原有的vector<uint32_t>重载:
// 新增重载 const float operator[](std::initializer_list<uint32_t> index) const { return operator[](std::vector<uint32_t>(index)); } // 原重载保留 const Tensor operator[](const std::vector<std::vector<uint32_t>>& ranges) const; const float operator[](const std::vector<uint32_t>& index) const;
此时obj[{0}]会自动匹配新增的重载,避免歧义。
3. 为二维vector版本添加显式包装类
创建一个包装类,将二维vector的参数包裹起来,通过explicit构造函数禁止隐式转换,强制用户显式调用该版本:
// 定义包装类 struct MultiRange { std::vector<std::vector<uint32_t>> ranges; explicit MultiRange(const std::vector<std::vector<uint32_t>>& r) : ranges(r) {} explicit MultiRange(std::initializer_list<std::vector<uint32_t>> il) : ranges(il) {} }; // 修改原二维vector版本的参数类型 const Tensor operator[](const MultiRange& ranges) const; // 保留原vector<uint32_t>版本 const float operator[](const std::vector<uint32_t>& index) const;
调用方式变为:
obj[{0}]; // 匹配vector<uint32_t>版本 obj[MultiRange{{0, 1}, {2, 3}}]; // 显式调用二维vector对应的版本
4. 使用C++20概念限制重载匹配
如果使用C++20及以上版本,可以用概念约束二维vector版本的参数,避免单元素初始化列表的匹配:
#include <concepts> // 约束参数为至少包含一个元素的二维vector template<typename T> concept MultiDimensionalRange = requires(T t) { { t } -> std::convertible_to<const std::vector<std::vector<uint32_t>>&>; !t.empty(); }; const Tensor operator[](MultiDimensionalRange auto&& ranges) const; const float operator[](const std::vector<uint32_t>& index) const;
不过这种方式对初始化列表的约束效果有限,更适合配合显式构造使用。
内容的提问来源于stack exchange,提问作者maciek97x
相关产品推荐
相关产品推荐

