问题描述:

I want to implement numerical `Vector`

which has several numerical operations.

I used template to define generic version of vector.

But implementation should be different with concrete implementation like `Vector3`

.

For example, `+`

operation would look like these.

**Vector3 implementation**

`Vector3 operator+(const Vector3& vec3) const{`

return Vector3(data[0]+vec3.data[0], data[1]+vec3.data[1], data[2]+vec3.data[2]);

}

**template implementation**

`GenericVector operator+(const GenericVector<T,N>& vec) const{`

GenericVector temp = *this;

for(int i=0;i<N;i++)

{

temp.data[i] += vec.data[i];

}

return temp;

}

Now that we cannot know how many `data`

it would have, we cannot define constructor like `Vector3(x,y,z)`

. That's why I introduced for loop in `+ operator`

overloading.

Actually when it comes to appearance of codes, `Vector3`

implementation looks better. But it cannot be scaled to different size vectors.

Template's implementation looks less nicer than that of `Vector3`

. But template version can easily scaled to many size vectors by doing like this.

`typedef GenericVector<double, 3> Vector3d;`

typedef GenericVector<double, 6> Vector6d;

**I'm not used to template of C++. Is there any one who can point problem of my implementation or understandings?**

My question is that in implementation of `+ operator`

in template version, is the choice of introducing for loop for accommodating unknown integer `N`

**right** or **the only choice**?

To simple one question,

**Can I avoid for loop in + operator?**

This is parts of my codes.

`template <typename T, int N>`

class GenericVector{

protected:

T data[N];

public:

GenericVector()

{

for(int i=0;i<N;i++)

{

data[i] = static_cast<T>(0);

}

}

GenericVector operator+(const GenericVector<T,N>& vec) const{

GenericVector temp = *this;

for(int i=0;i<N;i++)

{

temp.data[i] += vec.data[i];

}

return temp;

}

//...

};

One approach to avoid the loops in the various operations is to *not* store an array but use inheritance and specialization to deal with the different number of arguments. Something along the lines of this:

```
template <typename T, int Size> class GVector;
template <typename T>
class GVector<T, 0> {
public:
GVector() {}
GVector& operator+= (GVector const&) { return *this; }
GVector operator+ (GVector const& other) const {
return GVector() += other;
}
// ...
};
template <typename T, int Size>
class GVector: public GVector<T, Size - 1> {
T value;
public:
GVector(): GVector<T, Size - 1>(), value() {}
template <typename Head, typename... Tail>
GVector(T const& head, Tail const&... tail)
: GVector<T, Size - 1>(tail...)
, value(head) {
}
GVector& operator+= (GVector const& other) {
this->value += other.value;
this->GVector<T, Size - 1>::operator+= (other);
return *this;
}
GVector operator+ (GVector const& other) const {
return GVector(*this) += other;
}
// ...
};
```

There's generally a tradeoff when making code more generic: you reduce code duplication when you can reuse your generic code with different parameters but it usually means somewhat more complex code than the non-generic version and also limits opportunities for optimization. Better compilers and newer C++ features help reduce the tradeoffs but they still exist.

To answer your question, yes it is possible to create a generic vector class that doesn't use `for`

loops to iterate over the elements of the vector. Using `for`

loops is an acceptable implementation, however in my experiments with a generic vector class I opted not to use them because I found with my compiler that they were not fully unrolled even in optimized builds.

Note - this code is mostly an experiment to investigate the tradeoffs in building a generic vector class. I wouldn't necessarily advocate using a design like this in production.

C++11 variadic templates offer a solution to your constructor problem although there are certain issues that come along with them:

```
template <typename T, size_t N>
class Vector {
public:
static const size_t dimension = N;
Vector() = default;
Vector(const Vector&) = default;
template <typename... Ts>
Vector(T t, Ts&&... ts)
: aw({t, std::forward<Ts>(ts)...}) {
static_assert(sizeof...(Ts) == N - 1, "Constructor must be passed N initializers.");
}
private:
struct ArrayWrapper {
T e_[N];
} aw; // ArrayWrapper lets us initialize in constructor initializer
};
```

They can also be used to avoid looping in operators:

```
template <size_t I, typename F, typename... Args>
auto apply(F f, Args&&... args) {
return f(args.e(I)...);
}
template <typename F, size_t... Is, typename... Args>
auto apply(F f, std::index_sequence<Is...>, Args&&... args) {
using vec = std::common_type_t<Args...>;
using resvec = Vector<decltype(apply<0>(f, args...)), vec::dimension>;
return resvec{apply<Is>(f, args...)...};
}
template <typename F, typename... Args>
inline auto memberwise(F f, const Args&... args) {
using vec = std::common_type_t<Args...>;
return apply(f, std::make_index_sequence<vec::dimension>{}, args...);
}
template <typename T, size_t N>
inline Vector<T, N> operator+(const Vector<T, N>& a, const Vector<T, N>& b) {
return memberwise(std::plus<>{}, a, b);
}
```

In my experiments with this approach I found this produces good code in optimized builds with my compiler but it adds quite a lot of overhead in non-optimized builds, more than using a `for`

loop.