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?
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).
I suggest:
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) { ... }
}
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)
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.
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?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.