问题
I am trying to overload the operator + and += for std::vector, and what I do is
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;
}
}
But I assume this is bad practice, because clang-tidy warns me "Modification of std namespace can result in undefined behavior". Is there other better practice in overloading operator for STL classes?
回答1:
Best practice is not to do it.
But if you really want to you still can: just don't put it in namespace std
.
And don't take your arguments by value, unless you're deliberately doing so in order to make the most of move semantics (which you're not).
回答2:
I suggest:
- Don't overload the operators. Create regular functions instead.
- Put the functions in a
namespace
specific to your app.
Example:
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) { ... }
}
回答3:
Inserting functions into std
makes your program ill formed, no diagnostic required.
In certain limited circumstances you may insert specializations into std
, but that cannot do what you want here.
So you cannot insert vec + vec
into std
.
Putting an operator in a different namespace is legal, but ill-advised. Operators do not work well when they cannot be found via ADL/Koenig lookup. Code that is seemingly reasonable, like std::accumulate( vec_of_vec.begin(), vec_of_vec.end(), std::vector<int>{} )
fails to compile, among other issues.
The short answer is, vector
isn't your type. Don't do this.
You can create helper functions elsewhere, like util::elementwise_add( vec, vec )
.
The std
did not implement +
because both concatination and elementwise operations where reasonable. valarray
does implement elementwise operations; possibly what you want is std::valarray<int>
instead of std::vector<int>
.
Failing all of this, you could write a named operator vec +by_elem+ vec
or inherit from std::vector
in your own namespace, use that type, and overload +
for your type. (Inheriting from std::vector
is pretty safe; so long as nobody plays with heap allocated raw pointers to std::vector
s or similar)
回答4:
Whether you implement addition as operator+(...)
or as a function add(...)
, you'd better do it this way:
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;
}
By taking the first vector by value (and not by const-ref) you'll force a compiler to make a copy for you automatically to hold the result.
Addition after reading this comment.
Due to left-to-right associativity of +
, an expression like a + b + c
is parsed as (a + b) + c
. Hence, if the first (and not the second) argument in operator+(... x, ... y)
is taken by value, the prvalue returned by a + b
can be moved into x
. Otherwise, unnecessary copies will be made.
回答5:
You may should create your own vector class inherits from std::vector and define the new operator
#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();
}
Edit: sry i did not know that this solution causes undefined behaviour. Then i would suggest a similar solution shown in the post above. But why do you need the plus operator? Isnt push_back good enough? You could implement a reference return value to continue the addition. So you can do things like that:
vec + 20 + 30;
to add two elements (20 and 30). This is less code but is is more readable?
来源:https://stackoverflow.com/questions/52103950/overload-operator-for-vector-namespace-std