Оператор перегрузки + для вектора: пространство имен std - PullRequest
0 голосов
/ 30 августа 2018

Я пытаюсь перегрузить оператор + и + = для std :: vector, и я делаю это

namespace std {
    template<class T>
    vector<T> operator+(vector<T> x, vector<T> y) {
        vector<T> result;
        result.reserve(x.size());
        for (size_t i = 0; i < x.size(); i++)
            result[i] = x[i] + y[i];
        return result;
   }
}

Но я предполагаю, что это плохая практика, потому что clang-tidy предупреждает меня "Модификация пространства имен std может привести к неопределенному поведению". Есть ли еще лучший метод перегрузки операторов для классов STL?

Ответы [ 5 ]

0 голосов
/ 30 августа 2018

Вставка функций в std делает вашу программу плохо сформированной, диагностика не требуется.

В определенных ограниченных обстоятельствах вы можете вставить специализации в std, но это не может делать то, что вы хотите здесь.

То есть вы не можете вставить vec + vec в std.

Помещение оператора в другое пространство имен допустимо, но не рекомендуется. Операторы не работают хорошо, когда их невозможно найти с помощью ADL / Koenig lookup. Код, который кажется разумным, например, std::accumulate( vec_of_vec.begin(), vec_of_vec.end(), std::vector<int>{} ), не компилируется, среди прочих проблем.

Краткий ответ: vector не ваш тип. Не делай этого.

Вы можете создавать вспомогательные функции в других местах, например util::elementwise_add( vec, vec ).

В std не реализовано +, поскольку разумны как конкатенационные, так и поэлементные операции valarray осуществляет поэлементные операции; возможно, что вы хотите, это std::valarray<int> вместо std::vector<int>.

В противном случае вы можете написать именованный оператор vec +by_elem+ vec или наследовать от std::vector в своем собственном пространстве имен, использовать этот тип и перегрузить + для вашего типа. (Наследование от std::vector довольно безопасно; пока никто не играет с кучей, выделенными необработанными указателями на std::vector с или аналогичными)

0 голосов
/ 30 августа 2018

Независимо от того, реализуете ли вы добавление как operator+(...) или как функцию add(...), вам лучше сделать это следующим образом:

template<class T>
std::vector<T> operator+(std::vector<T> x, const std::vector<T>& y) {
    assert(x.size() == y.size());
    for (std::size_t i = 0; i < x.size(); ++i)
        x[i] += y[i];
    return x;
}

Взяв первый вектор по значению (а не по const-ref), вы заставите компилятор автоматически сделать копию для хранения результата.

Добавление после прочтения этот комментарий .

Из-за ассоциативности слева направо + выражение вроде a + b + c анализируется как (a + b) + c. Следовательно, если первый (а не второй) аргумент в operator+(... x, ... y) взят по значению, prvalue , возвращаемое a + b, можно переместить в x. В противном случае будут сделаны ненужные копии.

0 голосов
/ 30 августа 2018

Я предлагаю:

  1. Не перегружайте операторов. Вместо этого создайте обычные функции.
  2. Поместите функции в namespace, специфичные для вашего приложения.

Пример:

namespace MyApp
{
   template <typename T>
   std::vector add(std::vector<T> const& lhs, std::vector<T> const& rhs) { ... }

   template <typename T>
   std::vector& append(std::vector<T>& lhs, std::vector<T> const& rhs) { ... }
}
0 голосов
/ 30 августа 2018

Вы можете создать свой собственный векторный класс-наследник от std :: vector и определить новый оператор

#include <iostream>
#include <vector>

template<class T>
class MyVec : public std::vector<T>
{
public:
    MyVec& operator+=(const T& add)
    {
        reserve(1);
        push_back(add);
        return *this;
    }
};

int main()
{
    MyVec<int> vec;
    vec += 5;
    vec += 10;

    for (auto& e : vec)
    {
        std::cout << e << "\t";
    }

    std::cin.get();
}

Редактировать : извините, я не знал, что это решение вызывает неопределенное поведение. Тогда я бы предложил аналогичное решение, показанное в посте выше. Но зачем вам оператор плюс? Достаточно ли хорош push_back? Вы можете реализовать возвращаемое значение для продолжения добавления. Таким образом, вы можете делать такие вещи:

vec + 20 + 30;

чтобы добавить два элемента (20 и 30). Это меньше кода, но он более читабелен?

0 голосов
/ 30 августа 2018

Лучшая практика - не делать этого.

Но если вы действительно хотите, вы все равно можете: просто не помещайте это в пространство имен std.

И не принимайте ваши аргументы по значению, если только вы не делаете это намеренно, чтобы максимально использовать семантику перемещения (которой вы не являетесь).

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