Почему бы не перегрузить оператор + =() для std::vector?

Я начал изучать С++, поэтому я не знаю из-за недостатка знаний/опыта, почему то, что кажется таким простым для новичков, как то, что я собираюсь описать, еще не в STL. Чтобы добавить вектор к другому вектору, вы должны ввести это:

v1.insert(v1.end(), v2.begin(), v2.end());

Мне интересно, просто ли люди в реальном мире перегружают оператор + =, чтобы сделать это менее подробным, например, с эффектом

template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) {
    v1.insert(v1.end(), v2.begin(), v2.end());
}

тогда вы можете

v1 += v2;

Я также настроил для push_back на "+ =" один элемент до конца. Есть ли какая-то причина, по которой эти вещи не должны выполняться или специально избегаются людьми, которые владеют С++?

Ответ 1

Это действительно случай, когда я хотел бы видеть эту функциональность в виде перегрузки append(). operator+= является двусмысленным, вы хотите добавить элементы каждого вектора друг к другу? Или вы хотите добавить?

Однако, как я уже сказал, я бы приветствовал: v1.append(v2); Это ясно и просто, я не знаю, почему его там нет.

Ответ 2

Я думаю, что основная причина заключается в том, что семантика += не очевидна. Здесь есть смысл, который у вас есть здесь, но есть также одинаково действительное значение, которое поэтапно добавляет каждый элемент векторов равного размера. Из-за этой двусмысленности я предполагаю, что они решили, что лучше полагаться на пользователя, чтобы называть insert на самом деле.

Ответ 3

Операторы должны быть перегружены только тогда, когда вы не изменяете значение этих операторов. *

Что это означает, например, если нет математического определения произведения двух объектов, не перегружайте оператор умножения для этих объектов. Если было математическое соответствие, перегрузка операторов может сделать класс более удобным для использования, позволяя выражать выражения в виде a * b + c, а не более подробные (a.multiply(b)). Add (c) Где используются операторы сложения и умножения, назначение и умножение должны быть намерены. Любое другое значение более чем вероятно смущает других. Некоторые другие типы, в которых операторы перегрузки допустимы (и, на мой взгляд, предпочтительнее), являются интеллектуальными указателями, итераторами, комплексными числами, векторами и бонусами.

Это следует из одной из целей дизайна С++, что должно быть возможно определить классы, которые так же просты в использовании, как встроенные типы. Конечно, есть операторы, которые вы можете определить на классах, которые также не являются математическими понятиями. Возможно, вы захотите перегрузить операторы == и!= Вместо написания метода isEqual и, возможно, захотите перегрузить =, потому что оператор назначения по умолчанию для компилятора не то, что вы хотите.

С другой стороны, перегрузка оператора, чтобы сделать что-то неожиданное, например определение ^ для перевода строки на японский, является неясной и опасной. Ваши коллеги-программисты не с удовольствием узнают, что то, что выглядело как эксклюзив или сравнение, на самом деле было чем-то совсем другим. Тогда решение состоит в том, чтобы написать классы, чтобы упростить запись clear и поддерживаемого кода, независимо от того, означает ли это, что оператор перегружает или избегает его.

Добавление двух векторов слишком неоднозначно для warrent, определяющих оператор. Как показали другие, многие люди имеют разные представления о том, что это означает, тогда как для строки общепризнано, что добавление двух строк вместе означает конкатенацию. В вашем примере не совсем ясно, хотите ли вы добавить компонентный мудрый add во все элементы, добавить элемент в конец или объединить два вектора вместе. Хотя это может быть более кратким, чтобы сделать это таким образом, использование перегрузки оператора для создания собственного языка программирования - не лучший способ.

* Да, я знаю, что Stroustrup перегружен < < и → выполнять потоковые операции, а не бит-сдвиги. Но они часто не использовались по сравнению с операторами арифметики и указателями, и можно утверждать, что теперь, когда все знают, как использовать cout, обычно понимают, что < и → - операторы ввода-вывода и экстрактора. (Первоначально он пытался использовать только < и > для ввода и вывода, но смысл этих операторов был настолько укоренен в каждом сознании, что код был нечитаемым.)

Ответ 4

В дополнение к тому, что другие упомянули об этом синтаксисе, не являясь интуитивным и, следовательно, подверженным ошибкам, он также противоречит правильному правилу проектирования, в котором применяются общие алгоритмы, применяемые к различным функциям контейнеров, а также специфичные для контейнера алгоритмы - функции-члены. Это означает, что большинство контейнеров соблюдают это правило, за исключением std::string, который получил много денег от Herb Sutter за его монолитный дизайн.