2016-11-15 1 views
2

То, что я хочу иметь: R = V + R = R + V. Как это сделать:Как определить (перегрузить) симметричный двоичный оператор между двумя классами в C++, принимая во внимание значения r?

R operator+(const R &r, const V &v) { return R(r) += v; } 
R operator+(R &&r, const V &v) { return R(r) += v; } 
R operator+(const R &r, V &&v) { return R(r) += v; } 
R operator+(R &&r, V &&v) { return R(r) += v; } 

R operator+(const V &v, const R &r) { return r + v; } 
R operator+(V &&v, const R &r) { return r + v; } 
R operator+(const V &v, R &&r) { return r + v; } 
R operator+(V &&v, R &&r) { return r + v; } 

Есть ли более короткий путь?

+0

связанный: http: // stackoverflow.com/questions/13166079/move-semantics-and-pass-by-rvalue-reference-in-overloaded-арифметика и https://stackoverflow.com/questions/2696156/how-to-reduce-redundant-code-when- add-new-c0x-rvalue-reference-operator-ove – NathanOliver

+0

, чтобы уточнить, является 'V' таким, что выполнение' r + v' выполняется быстрее, если 'v' можно вывести из? –

+0

Я предполагаю, что не копирование v или r быстрее, чем копирование. (Так что, если мне не нужно его копировать, я не должен). Здесь я также предположил, что у меня есть копирование и перемещение конструкторов, поэтому, когда я пишу R (r), он либо копирует его, либо перемещает его, в зависимости от того, является ли r значением r - по крайней мере, это было моим намерением. – Jecke

ответ

2

Поскольку вы будете создавать экземпляр r либо из const R& или R&& в любом случае, это будет сократить на 4 линии:

R operator+(R r, const V& v) { return std::move(r += v); } 
R operator+(R r, V&& v) { return std::move(r += std::move(v)); } 

R operator+(const V& v, R r) { return std::move(r += v); } 
R operator+(V&& v, R r) { return std::move(r += std::move(v)); } 

Однако, я думаю, что это достаточно для вас во всех случаях, если ваш R::operator+=(V&&) нет разницы реализация от R::operator+=(const V&):

R operator+(R r, const V& v) { return std::move(r += v); } 

R operator+(const V& v, R r) { return std::move(r += v); } 

Мой ответ был ш когда я не знал об этой реализации:

R operator+=(R&& r, const V& v) 
R operator+=(R&& r, V&& v) 

Ответ Yakk лучше, если учитывать эти функции.

+1

Если '+ =' может принимать 'V'' && '. Также обратите внимание, что вы должны «переместить» в '+ =' выше для 'r', иначе' + = 'не имеет способа узнать, что он может повторно использовать хранилище или вернуть значение r. – Yakk

+0

@Yakk я добавил это примечание. – Danh

+0

Откуда вы знаете, что я всегда буду создавать копию 'r'? Если бы у меня было 'R r = some_function_returning_R() + v', то не было бы' some_function_returning_R() 'быть rvalue, и тогда я не мог бы добавить' v' к нему, а затем вернуть его в результате ' operator + (R && r, const V & v) ', не создавая никакой копии' r'? – Jecke

1

Предполагая:

R& operator+=(R& r, const V& v); 
R& operator+=(R& r, V&& v); 
R operator+=(R&& r, const V& v) { r += v; return std::move(r); } 
R operator+=(R&& r, V&& v) { r += std::move(v); return std::move(r); } 

мы должны иметь:

R operator+(R r, V const& v) { return std::move(r)+=v; } 
R operator+(R r, V && v) { return std::move(r)+=std::move(v); } 
R operator+(V const& v, R r) { return std::move(r)+=v; } 
R operator+(V && v, R r) { return std::move(r)+=std::move(v); } 

где я предполагаю, что R дешев передвигающийся, в то время как += с V&& лишь незначительно более эффективным, чем V const&.

Обратите внимание, что возвращаемое значение R operator+=(R&& r, ?) должно быть значением. Я реализую его в терминах +=(const&,?), а затем просто перейду в возвращаемое значение.

Это означает, что вы должны реализовать два оператора += за пределами вышеуказанного шаблона.

Если нет никакой выгоды от перемещенного-от V мы получаем:

R& operator+=(R& r, const V& v); 
R operator+=(R&& r, const V& v) { r += v; return std::move(r); } 
R operator+(R r, V const& v) { return std::move(r)+=v; } 
R operator+(V const& v, R r) { return std::move(r)+=v; } 

3 шаблонные, одна фактически реализовано функции.

Если вы не любите R operator+=(R&& r, const V& v) мы можем переписать это так:

R& operator+=(R& r, const V& v); 
R operator+(R r, V const& v) { return std::move(r+=v); } 
R operator+(V const& v, R r) { return std::move(r+=v); } 

и аналогично для V&& случаях, если это необходимо:

R& operator+=(R& r, V&& v); 
R operator+(R r, V&& v) { return std::move(r+=std::move(v)); } 
R operator+(V&& v, R r) { return std::move(r+=std::move(v)); } 

Мы делаем копию R в подписи operator+, а чем внутренне; если мы все равно его скопируем, возможно, также сделаем это в подписи.

Want speed? Pass by value. - это метод, используемый для удаления перегрузок R const& и R&& как избыточных.

+0

Хмм, 1. это 'return std :: move (r) + = v;' отличается от 'return std :: move (r + = v) '? Если да, то как? 2. Не следует ли рассматривать возможность «R-оператора + (R && r,?)»? – Jecke

+0

Я не вижу причины для реализации «R operator + = (R && r, const V & v)» или «R operator + = (R && r, V && v)». Оператор '+ =' подразумевает, что вы изменяете левый операнд. В противном случае вы будете использовать '+'. Почему вы должны использовать '+ =' для перезаписывания левого операнда, если впоследствии вы удаляете содержимое? – JojOatXGME

+0

Не закончилось ли вызывать «R & operator + = (R & r, const V & v);' in 'R operator + (R r, V const & v) {return std :: move (r) + = v;}'? любая выгода? – Danh

Смежные вопросы