Here is some context :
I need to overload some operators to act on std::vector operands. I decided against implementing directly the operator overloads in the global scope, as I believe it would be a bad practice due to possible conflicts. As a result, I decided to implement a templated class which :
- Behaves as much as possible like a std::vector
- Allows the overloading of the operator in a transparent way
The initial idea was to inherit from std::vector but I quickly realized it is not recommended. I therefore decided to create a class which holds a std::vector data member and implements an interface that makes it as transparent to the user as possible.
Here is a snippet of what I came up with :
template<typename T>
class Vector {
public:
Vector() = default;
~Vector() = default;
Vector(std::initializer_list<T> list) :data(list) {}
template<typename... Args>
Vector(Args... args) : data(args...){}
/* All std::vector functions with parameters and return value will look like this*/
template<typename...Args>
auto reserve(Args... args) {
return data.reserve(args...);
}
/* All std::vector functions with parameters and void return value will look like this*/
template<typename... Args>
void resize(Args... args) {
data.resize(args...);
}
/* All std::vector functions without parameter and void return value will look like this*/
void clear() {
data.clear();
}
/* All std::vector functions with return value will look like this*/
Vector& operator=(Vector const & other) {
data = other.getData();
return *this;
}
size_t size() const {
return data.size();
}
std::vector<T> & getData() {
return data;
}
std::vector<T> const & getData() const {
return data;
}
T & operator[](size_t i) {
return data[i];
}
T const & operator[](size_t i) const {
return data[i];
}
/* All std::vector functions without args and with return value will look like this*/
auto begin() {
return data.begin();
}
private:
std::vector<T> data;
};
And the overloaded operators would be written like :
template <typename T>
void operator -= (Vector<T>& a, const Vector<T>& b) {
if (a.size() != b.size()) {
throw std::length_error("void operator -= (Vector<T>& a, const Vector<T>& b)\nBoth Vector<T> operands should have the same size");
}
for (int i = 0; i < a.size(); ++i) {
a[i] -= b[i];
}
}
My question is the following : how viable is this strategy ? Is there something inherently wrong with that ?
I do feel that there is quite a big amount of boilerplate code (all functions with arguments and with return value will look in a certain way, and only the name of the functions that will be passed to the data member will change), do you see a potential improvement possible there ?