算术复合运算符重载为非成员



我编写了一个模板化类,它按照这个特别有见地的答案提供的准则实现了一些基本的运算符重载:

template <typename _type>
class myClass {
// ...
template<_input_type> myClass<_type>& operator+=(const myClass<_input_type>& _other);
// ...
}

将算术复合运算符写为成员:

template <typename _type>
template <typename _input_type>
myClass<_type>& myClass<_type>::operator+=(const myClass<_input_type>& _other) { 
static_assert(std::is_arithmetic<_type>::value);
// do stuff
return *this;
};

以及作为非成员的非复合运算符:

template <typename _type, typename _input_type> 
inline myClass<_type> operator+(myClass<_type>& _o1, myClass<_input_type> _o2) { 
return _o1+=_o2;
};

但是,由于模板myClass可用于多种数据类型,其中一些是非数字的,无法处理+-*/运算符,因此我想知道将所有运算符重载代码实现为非成员函数有什么缺点,例如我可以将它们全部放在一个单独的头文件中,只需要在需要时包含用于算术功能。我知道一种解决方案是定义一个仅实现运算符重载的新class myNumericClass : public myClass,但这需要一个新的类型名并限制myClass的多功能性。

将复合赋值实现为非成员的主要缺点是与简单(复制或移动(赋值运算符不一致。一个简单的复制或移动赋值(即operator=(必须作为成员函数实现,否则编译器将直接拒绝代码。

鉴于复制/移动赋值必须作为成员函数实现,许多人也喜欢将复合赋值实现为成员。

顺便说一句,这段代码:

template <typename _type, typename _input_type> 
inline myClass<_type> operator+(myClass<_type>& _o1, myClass<_input_type> _o2) { 
return _o1+=_o2;
};

。IMO,是非常不可取的。一般样式很好,但您混淆了按值传递的操作数和按引用传递的操作数。结果,它可能不必要地效率低下,并且(更糟糕的是(修改了它的左操作数,所以它真的像+=而不是+。你几乎肯定想要的更像是这样:

template <typename _type, typename _input_type> 
inline myClass<_type> operator+(myClass<_type> _o1, myClass<_input_type> const &_o2)
{ 
return _o1+=_o2;
};

这里我们按值传递左操作数,因此当调用函数时,将从左操作数创建并初始化临时值。然后,我们修改该临时值(更改原始值(并返回它。由于我们确实返回了它,因此将有copy elision(在较旧的编译器上是可选的,但从C++17开始是强制性的(,这意味着它通常实际上只是对目标的引用,因此有效地,如下所示:a = b + c;将被视为:a = b; a += c;。由于我们只需要正确操作数的先前值,因此我们将其作为引用传递给 const 以避免不必要的复制(尽管,根据类型,通过引用传递可能没有足够的收益来关心,甚至可能是损失。但这可能是一个很大的收益,很少超过一个小损失(。

最新更新