c – 可以将重载运算符重构为非成员函数中断任何代码吗?
作者:互联网
考虑具有重载加法运算符=和的遗留类模板
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;
}
它看起来足够安全,因为所有有效的表达式使用和=保留其原始的语义含义.
问题:运算符从成员函数重构为非成员函数会破坏任何代码吗?
破损的定义(最差到最好)
>新代码将编译在旧方案下无法编译
>旧代码将无法编译在旧方案下编译
>新代码将静默调用另一个运算符(从通过ADL拖入的基类或关联的名称空间)
解决方法:
摘要
答案是,是的,总会有破损.关键因素是函数模板参数推导不考虑隐式转换.我们考虑三种场景,涵盖了重载运算符可以采用的三种语法形式.
这里我们在X< T>中使用隐式构造函数.本身.但即使我们使该构造函数显式化,用户也可以添加到X< T>的命名空间中. C类< T>它包含表单运算符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
标签:c,operator-overloading,implicit-conversion,argument-dependent-lookup,non-member- 来源: https://codeday.me/bug/20191007/1868595.html