patterncppMinor
Heavily templated mathematical vector class
Viewed 0 times
templatedheavilyclassvectormathematical
Problem
I started to write a library for linear algebra for personal use, but also for revitilization of my C++.
Below is the first class of this library, a templated vector class, which is templated over the type of the elements as well as the size. It supports all common operations of vectors as member functions and also as static functions, to support different coding preferences. I also overloaded the operators, that make sense in my opinion. I templated over the size because I need the byte-size of a float vector to be 4*n.
Generally all suggestions and comments are more than welcome, but I also have a few points I specifically want to ask about:
Thanks for your time!
```
template
class Vector {
private:
std::array data;
public:
Vector() : Vector(T(0)) {}
Vector(T value) {
for (int i = 0; i data) {
this->data = data;
}
public:
Vector& addTo(const Vector& summand) {
for (int i = 0; i data[i] += summand[i];
}
return *this;
}
Vector& subtractFrom(const Vector& subtrahend) {
for (int i = 0; i data[i] -= subtrahend[i];
}
return *this;
}
template
Vector& multiplyBy(scalar factor) {
for (int i = 0; i & multiplyBy(const Vector& factor) {
for (int i = 0; i
Vector& divideBy(scalar divisor) {
this->multiplyBy(1 / divisor);
return *this;
}
template
Vector& divideBy(const Vector& divisor) {
for (int i = 0; i
Below is the first class of this library, a templated vector class, which is templated over the type of the elements as well as the size. It supports all common operations of vectors as member functions and also as static functions, to support different coding preferences. I also overloaded the operators, that make sense in my opinion. I templated over the size because I need the byte-size of a float vector to be 4*n.
Generally all suggestions and comments are more than welcome, but I also have a few points I specifically want to ask about:
- Interface-Design: Choice of providing both non-static and static versions of most operations, and implementing operators in terms of the static functions
- Inlining: Did I miss functions, that can be inlined without further thought? Should I remove inlining from some functions
- Functionality: Did I miss functions/operators that the class should have?
- Function naming: I'm not completely satisfied with some namen, but can't think of better ones, that are still exact. Maybe someone has suggestions?
Thanks for your time!
```
template
class Vector {
private:
std::array data;
public:
Vector() : Vector(T(0)) {}
Vector(T value) {
for (int i = 0; i data) {
this->data = data;
}
public:
Vector& addTo(const Vector& summand) {
for (int i = 0; i data[i] += summand[i];
}
return *this;
}
Vector& subtractFrom(const Vector& subtrahend) {
for (int i = 0; i data[i] -= subtrahend[i];
}
return *this;
}
template
Vector& multiplyBy(scalar factor) {
for (int i = 0; i & multiplyBy(const Vector& factor) {
for (int i = 0; i
Vector& divideBy(scalar divisor) {
this->multiplyBy(1 / divisor);
return *this;
}
template
Vector& divideBy(const Vector& divisor) {
for (int i = 0; i
Solution
-
Take constant arguments by
also, you may want these constructors to be
-
Implement operations via
I don't think that the operation
-
It makes sense to overload
-
The cross product is best implemented as standalone function for 3D vectors only, avoiding the need for
-
You should follow the example of
-
You may add some functionality to apply an arbitrary function to each element:
You may also have similar methods for generating another
-
I would use
Take constant arguments by
const reference, e.g.template
Vector::Vector(std::array const&_data) : data(_data) {}
template
Vector::Vector(T const&_datum) : data(_datum) {}also, you may want these constructors to be
explicit (to disallow implicit usage as converting constructors).-
Implement operations via
operators only. IMHO, there is not benefit in using the named functions. An implementation via expression templates is rather complicated and only really required in highly performance critical paths (when you may want to do things differently anyway).I don't think that the operation
scalar/Vector should be supported. This is mathematically/syntactically wrong/dubious.-
It makes sense to overload
abs(Vector const&vec) to return vec.length().-
The cross product is best implemented as standalone function for 3D vectors only, avoiding the need for
static_assert. You may also overload the operator^ for this purpose (but consider operator preference).-
You should follow the example of
std::vector to provide memory access via operator[] w/o checking for out-of-bounds error and via member at() with out-of-bounds error. Don't merely assert, but throw std::out_of_range. (assert should only be used to check internally expected invariants, not user input.)-
You may add some functionality to apply an arbitrary function to each element:
template
class Vector {
template
Vector& apply(Func const&func) noexcept(noexcept(func))
{
for(uint32_t i=0; i!=size; ++i)
func(data[i]);
return*this;
}
};You may also have similar methods for generating another
Vector by element-wise operations ...-
I would use
template alias instead of your typedefs:template using Vector2 = Vector;Code Snippets
template<typename T, uint32_t size>
Vector<T,N>::Vector(std::array<T, size> const&_data) : data(_data) {}
template<typename T, uint32_t size>
Vector<T,N>::Vector(T const&_datum) : data(_datum) {}template<typename T, uint32_t size>
class Vector {
template<typename Func>
Vector& apply(Func const&func) noexcept(noexcept(func))
{
for(uint32_t i=0; i!=size; ++i)
func(data[i]);
return*this;
}
};template<typename T> using Vector2 = Vector<T,2>;Context
StackExchange Code Review Q#131334, answer score: 2
Revisions (0)
No revisions yet.