简体   繁体   English

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

[英]Arithmetic compound operator overload as non-member

I've written a templated class that implements some basic operator overloading, following the guidelines provided by this particularly insightful answer : 我按照这个特别有见地的答案提供的指导方针,编写了一个模板类,该类实现一些基本的运算符重载:

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

with the arithmetic compound operators written as members: 将算术复合运算符写为成员:

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;
};

and the non-compound operator as a non-member: 非复合运算符作为非成员:

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

However, due to the template myClass can be used for several data types, some of them non-numeric that can't handle + , - , * or / operators, and as such I was wondering what are the downsides of implementing all operator overloading code as non-member functions, so that eg I could just placed them all on a separate header file that would only need to be included if there is need for arithmetic functionality. 但是,由于模板myClass可用于多种数据类型,其中一些非数字类型无法处理+-*/运算符,因此我想知道实现所有运算符重载的不利之处代码作为非成员函数,因此例如我可以将它们全部放在单独的头文件中,仅在需要算术功能时才需要将其包括在内。 I understand one solution would be to define a new class myNumericClass : public myClass that just implements operator overloading, but that would require a new typename and limit the versatility of myClass . 我知道一种解决方案是定义一个新class myNumericClass : public myClassclass myNumericClass : public myClass仅实现运算符重载,但是这需要一个新的typename并限制myClass的多功能性。

The primary shortcoming of implementing compound assignment as a non-member is inconsistency with the simple (copy or move) assignment operator. 将复合分配作为非成员实现的主要缺点是与简单的(复制或移动)分配运算符不一致。 A simple copy or move assignment (ie, operator= ) must be implemented as a member function, or the compiler will outright reject the code. 一个简单的复制或移动分配(即, operator=必须被实现为一个成员函数,或编译器将直接拒绝的代码。

Given that copy/move assignment must be implemented as member functions, many prefer to implement compound assignment as members as well. 鉴于必须将复制/移动分配实现为成员函数,因此许多人也希望将复合分配也实现为成员。

As an aside, this code: 顺便说一句,此代码:

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

...is, IMO, highly inadvisable. ……是国际海事组织(IMO)的,非常不可取的。 The general style is fine, but you've mixed up which operand to pass by value and which to pass by reference. 通用样式很好,但是您混淆了要按值传递哪个操作数和按引用传递哪个操作数。 As a result, it may be needlessly inefficient, and (much worse) modifies its left operand, so it really acts like += instead of + . 结果,它可能不必要地效率低下, 并且 (更糟的是)修改了它的左操作数,因此它的行为实际上类似于+=而不是+ What you almost certainly want is more like this: 您几乎肯定想要的是这样的:

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

Here we pass the left operand by value, so when the function is called a temporary value is created and initialized from the left operand. 在这里,我们按值传递左操作数,因此在调用该函数时,会从左操作数创建并初始化一个临时值。 We then modify that temporary value ( without changing the original) and return it. 然后,我们修改该临时值( 更改原始值)并返回它。 Since we do return it, there will be copy elision (optional on older compilers, but mandatory since C++17) which means it'll normally really just be a reference to the destination, so effectively, something like: a = b + c; 由于我们确实返回了它,所以会有复制省略号(在旧的编译器上是可选的,但是自C ++ 17起是必需的),这意味着它通常实际上只是对目标的引用,因此有效地类似于: a = b + c; will be treated as: a = b; a += c; 将被视为: a = b; a += c; a = b; a += c; . Since we only need the previous value of the right operand, we pass it as a reference to const to avoid an unnecessary copy (though, depending on the type, passing by reference may not gain enough to care about, or could even be a loss. But it can be a big gain, and is rarely more than a tiny loss). 由于我们只需要右操作数的前一个值,因此我们将其作为对const的引用来避免不必要的复制(尽管根据类型的不同,按引用传递可能不会获得足够的关注,甚至可能会造成损失但它可以带来很大的收益,而且损失很少。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM