如何解决C++模板运算符重载的调用歧义问题
问题背景
查阅大量相关资料后发现,其他开发者遇到的同类运算符重载问题,和我的实际场景均存在差异。
为简化问题描述,先做前提说明:我定义了模板结构体Complex<X>,需要为其重载加法运算符,支持两类运算场景:一是和实数类型的运算,二是和其他Complex实例的运算。按照设计规则,double类型或Complex<double>与Complex<float>进行运算时(无论运算符哪一侧为上述类型),返回值类型都应为Complex<double>。
我目前使用类模板推导指南实现该类型提升逻辑,效果尚可,除此之外可选的实现方案还有std::common_type_t<X,Y>、decltype(std::declval<X>()+std::declval<Y>())等。
已编写的重载版本
我先后尝试过以下几类运算符重载实现:
// (1) 成员重载:右操作数为当前实例的模板参数类型X auto operator+(X const&) // (2) 友元非模板重载:左操作数为X类型,右操作数为Complex<X>类型 friend auto operator+(X const&, Complex<X> const&) // 模板成员重载:右操作数为任意类型Y template<class Y> auto operator+(Y const&) // (3) 模板成员重载:右操作数为任意Complex<Y>实例 template<class Y> auto operator+(Complex<Y> const&) // (4) 模板友元重载:左操作数为任意类型Y,右操作数为Complex<X>实例 template<class Y> friend auto operator+(Y const&, Complex<X> const&)
现存问题
- 若仅实现(1)(2)类非模板重载,
Complex<float>的运算符会将传入的double类型参数隐式转换为float处理,丢失精度,不符合类型提升的设计要求 - 若改为实现模板类重载,当
Complex<double>参与加法运算时,会在非模板版本(2)、模板成员版本(3)、模板友元版本(4)三个重载之间产生调用歧义 - 非模板运算符本身不会出现这类歧义,但实际场景中需要支持的数值类型过多,无法逐一枚举定义所有对应非模板重载
已尝试的排查方案
- 最初猜测歧义问题源于CV限定符和引用类型的匹配规则,但将(1)(2)类重载的参数改为按值传递X类型后,问题仍然存在,该表现和
auto x不会推导为引用类型的规则恰好相反 - 曾尝试在(1)(2)类重载中添加
static_assert(std::is_arithmetic_v<Y>)这类静态断言限制参数类型,但静态断言不会参与重载决议流程,无法起到消除重载歧义的作用
内容的提问来源于stack exchange,提问作者John P
相关产品推荐
相关产品推荐

