Tem*_*Rex 9 c++ operator-overloading implicit-conversion argument-dependent-lookup non-member-functions
考虑重载加法运算的遗留类模板+=和+
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;
};
Run Code Online (Sandbox Code Playgroud)
在代码审查时,观察到它+是可实现的+=,为什么不使它成为非成员(并保证左右参数的对称性)?
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;
}
Run Code Online (Sandbox Code Playgroud)
它看起来足够安全,因为所有有效的表达式都使用+并+=保留了它们原有的语义含义.
问题: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 */ }
//...
};
Run Code Online (Sandbox Code Playgroud)
这段代码将允许这样的表达
T t;
X<T> x;
x + t; // OK, implicit conversion on non-deduced rhs
t + x; // ERROR, no implicit conversion on deduced this pointer
Run Code Online (Sandbox Code Playgroud)
template<class T>
class X
{
public:
/* implicit */ X(T val) { /* bla */ }
//...
friend
X<T> operator+(X<T> const& lhs, X<T> const& rhs) { /* bla */ }
//...
};
Run Code Online (Sandbox Code Playgroud)
由于该friend函数不是模板,因此不会发生参数推导,并且 lhs 和 rhs 参数都考虑隐式转换
T t;
X<T> x;
x + t; // OK, implicit conversion on rhs
t + x; // OK, implicit conversion on lhs
Run Code Online (Sandbox Code Playgroud)
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 */ }
Run Code Online (Sandbox Code Playgroud)
在这种情况下,lhs 和 rhs 参数都经过参数推导,并且都不考虑隐式转换:
T t;
X<T> x;
x + t; // ERROR, no implicit conversion on rhs
t + x; // ERROR, no implicit conversion on lhs
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
208 次 |
| 最近记录: |