Перегрузка арифметического составного оператора как не члена - PullRequest
0 голосов
/ 25 октября 2018

Я написал шаблонный класс, который реализует некоторую базовую перегрузку операторов, следуя рекомендациям этого особенно проницательного ответа :

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.

1 Ответ

0 голосов
/ 25 октября 2018

Основным недостатком реализации составного присваивания в качестве нечленов является несоответствие с простым оператором присваивания (копирования или перемещения).Простое назначение копирования или перемещения (т. Е. operator=) должно быть должно быть реализовано как функция-член, иначе компилятор прямо отклонит код.

Учитывая, что назначение копирования / перемещения должны быть реализованы как функции-члены, многие предпочитают также выполнять составные присваивания в качестве членов.

Кроме этого, этот код:

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

... is, IMOочень нежелательно.Общий стиль хорош, но вы перепутали, какой операнд должен передаваться по значению, а какой - по ссылке.В результате он может быть излишне неэффективным, и (намного хуже) изменяют свой левый операнд, поэтому он действительно действует как += вместо +.То, что вам почти наверняка нужно, больше похоже на это:

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

Здесь мы передаем левый операнд по значению, поэтому при вызове функции временное значение создается и инициализируется из левого операнда.Затем мы изменяем это временное значение ( без изменения оригинала) и возвращаем его.Так как мы его возвращаем, будет elision copy (необязательный для старых компиляторов, но обязательный, начиная с C ++ 17), что означает, что обычно он будет просто ссылкой на место назначения, так эффективно, что-то вроде: a = b + c; будеттрактоваться как: a = b; a += c;.Так как нам нужно только предыдущее значение правого операнда, мы передаем его как ссылку на const, чтобы избежать ненужной копии (хотя, в зависимости от типа, передача по ссылке может не набрать достаточного количества для заботы или даже может быть потерей).Но это может быть большой выигрыш, и редко это больше, чем крошечная потеря).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...