自定义aRef类转换运算符重载在GCC与Clang上的行为差异问题
问题1:编译器行为差异的性质
该差异属于C++标准允许的正常行为,并非GCC缺陷。
当使用非const的aRef临时对象初始化值类型T时,两个转换运算符均为可行候选:
- 调用
operator T&()得到T类型左值,再拷贝构造目标值 - 调用
operator const T&()得到const T类型左值,再拷贝构造目标值
C++标准中这两种转换序列的优先级没有明确的高低之分,不同编译器可以做不同的实现决策,因此GCC选择非const版本、Clang选择const版本都符合标准要求。
问题2:兼容多编译器的修改方案
只需要做几处小修改即可让GCC的行为符合预期,同时保留所有原有功能:
- 给
operator const T&()加上const成员限定符,明确该转换运算符不会修改aRef本身 - 将结构体中const版本的
operator[]返回值改为const aRef,确保const对象返回的aRef只能调用const限定的转换运算符 - (可选)新增值转换重载,让值类型初始化场景的行为更明确
修改后核心代码示例
struct aRef { constexpr aRef() : ptr(nullptr), is_const(false), type(typeid(void)) { } template<typename T> explicit aRef(T* in) : ptr(in), is_const(false), type(typeid(T)) { } template<typename T> explicit aRef(const T* in) : ptr(const_cast<T*>(in)), is_const(true), type(typeid(T)) { } template<typename T> operator T&() { if (is_const) throw std::bad_cast{}; if (typeid(T) == type) return *static_cast<T*>(ptr); else throw std::bad_cast{}; } // 新增const成员限定符 template<typename T> operator const T&() const { if (typeid(T) == type) return *static_cast<T*>(ptr); else throw std::bad_cast{}; } // 可选新增值转换重载,优先匹配值初始化场景 template<typename T> operator T() const { if (typeid(T) == type) return *static_cast<T*>(ptr); else throw std::bad_cast{}; } private: void* const ptr; const bool is_const; std::type_info const& type; }; struct MDATA { double A; double B; aRef operator[](const std::string& key) { if (key == "A") return aRef(&A); else if (key == "B") return aRef(&B); else return aRef(); } // 返回值改为const aRef const aRef operator[](const std::string& key) const { if (key == "A") return aRef(&A); else if (key == "B") return aRef(&B); else return aRef(); } };
修改后GCC和Clang的运行结果会完全一致,全部符合预期行为。
内容的提问来源于stack exchange,提问作者user17071443
相关产品推荐
相关产品推荐

