考虑一个拥有重载加法运算符
在代码审查中,观察到
+=
和+
的传统类模板。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引入的相关命名空间)
inline
主要用于指示函数不受ODR(One Definition Rule)的约束(允许在多个翻译单元中定义函数而不会出错),而不是表示该函数应该被内联(标准并不要求编译器遵守inline
)。由于模板的隐式实例化已经免除了ODR的限制,因此inline
实际上并没有什么作用。它们不是同一件事,但它们具有相同的效果(再次强调,这只针对隐式实例化)。 - cdhowie+
作为成员函数引用:X<Foo> z = x.operator+(y);
,那么它可能会在编译时破坏一些东西。但这与 ADL 无关,并且极不可能遇到这种情况。 - misberner