9

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

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 拖入的基类或关联命名空间)
4

1 回答 1

3

概括

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

在这里,我们在自身内部使用了一个隐式构造函数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
于 2014-09-29T18:09:48.573 回答