繁体   English   中英

可以将重载运算符重构为非成员函数会破坏任何代码吗?

[英]Can refactoring an overloaded operator into a non-member function break any code?

考虑具有重载加法运算符+=+的遗留类模板

template<class T>
class X
{
public:
    X() = default;
    /* implicict */ X(T v): val(v) {}

    X<T>& operator+=(X<T> const& rhs)       { val += rhs.val; return *this; }
    X<T>  operator+ (X<T> const& rhs) const { return X<T>(*this) += rhs;    } 

private:
    T val;
};

在代码审查时,观察到+可以用+= ,那么为什么不使它成为非成员(并保证左右参数的对称性)?

template<class T>
class X
{
public:
    X() = default;
    /* implicit */ X(T v): val(v) {}

    X<T>& operator+=(X<T> const& rhs)       { val += rhs.val; return *this; }

private:
    T val;
}; 

template<class T>
X<T> operator+(X<T> const& lhs, X<T> const& rhs)
{ 
    return X<T>(lhs) += rhs; 
}

它看起来很安全,因为使用++=所有有效表达式都保留了它们原始的语义含义。

问题operator+从成员函数重构为非成员函数会破坏任何代码吗?

破损的定义(最差到最好)

  • 新代码将编译在旧方案下无法编译
  • 旧代码将无法编译在旧方案下编译
  • 新代码将默默调用另一个operator+ (从通过ADL拖入的基类或关联的名称空间)

摘要

答案是,是的,总会有破损。 关键因素是函数模板参数推导不考虑隐式转换。 我们考虑三种场景,涵盖了重载运算符可以采用的三种语法形式。

这里我们在X<T>本身内部使用隐式构造函数。 但即使我们使构造函数explicit ,用户也可以在X<T>的名称空间中添加一个类C<T> ,其中包含表单operator X<T>() const的隐式转换。 在这种情况下,下面的情景将继续存在。

非成员友元函数在允许lhs参数隐式转换的意义上打破最少,这些转换不会为类模板的成员函数进行编译。 非成员函数模板打破了rhs参数的隐式转换。

类模板的成员函数

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
    X<T> operator+(X<T> const& rhs) { /* bla */ }
//...
};

这段代码将允许表达式

T t;
X<T> x;
x + t;  // OK, implicit conversion on non-deduced rhs
t + x;  // ERROR, no implicit conversion on deduced this pointer

非会员朋友功能

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
    friend 
    X<T> operator+(X<T> const& lhs, X<T> const& rhs) { /* bla */ }
//...
};

由于friend函数不是模板,因此不会发生参数推导,并且lhs和rhs参数都考虑隐式转换

T t;
X<T> x;
x + t;  // OK, implicit conversion on rhs
t + x;  // OK, implicit conversion on lhs

非会员功能模板

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
};

template<class T> 
X<T> operator+(X<T> const& lhs, X<T> const& rhs) { /* bla */ }

在这种情况下,lhs和rhs参数都经过参数推导,并且都没有考虑隐式转换:

T t;
X<T> x;
x + t;  // ERROR, no implicit conversion on rhs
t + x;  // ERROR, no implicit conversion on lhs

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM