I am relatively new to c++ templates, and am implementing some numerical routines. In particular, I have been looking through some code whose style is such that if it were to define a vector, it would be as
template <class Field>
class Vector2
{
private:
std::vector<Field> container;
public:
Vector2(size_t size) : container(std::vector<Field>(size, Field(0))) {}
Vector2(const Vector2<Field> &source) : container(source.container) {}
Field & operator[](size_t index) { return container.at(index); }
const Field & operator[](size_t index) const { return container.at(index); }
Vector2<Field> operator+( const Vector2<Field> & rhs) const {
if (rhs.container.size() != container.size())
throw new std::invalid_argument("wrong size");
Vector2<Field> sum(*this);
for (int i = 0; i < container.size(); i++)
sum[i] += rhs[i];
return sum;
}
};
However, if I were designing the class template, I would have chosen to specify the size in the template parameter:
template <int size, class Field>
class Vector1
{
private:
std::vector<Field> container;
public:
Vector1() : container(std::vector<Field>(size, Field(0))) {}
Vector1(const Vector1<size, Field> &source) : container(source.container) {}
Field & operator[](size_t index) { return container.at(index); }
const Field & operator[](size_t index) const { return container.at(index); }
Vector1<size, Field> operator+( const Vector1<size, Field> & rhs) const {
Vector1<size, Field> sum;
for (int i = 0; i < size; i++)
sum[i] += rhs[i];
return sum;
}
};
My thinking is that this would prevent things like adding two vectors of different dimensions, since they would be different classes. In particular, something like
Vector1<double> a (3);
Vector1<double> b (4);
Vector1<double> c = a + b;
would need run-time checking of the sizes, yet
Vector2<3,double> a;
Vector2<4,double> b;
Vector2<5,double> c = a + b;
won't even compile. Since this code is part of a numerical analysis package, execution speed is of the essence, and I have to assume that the authors would have considered such things. This style is used throughout the code for vectors, matrices, and other objects that are to be interpreted as elements of numerically-parametrized sets (i.e. vector spaces of varying dimension).
So, my question is,
Are there any execution-speed considerations that would imply a preference for the constructor-parameter method vs. the template-parameter method?
Of course. If the vector size is a runtime parameter, then binary operations must check at runtime that operand sizes agree.
Ideally, a C++ numerical package should provide templates with runtime-specified sizes and compile-time-specified sizes, and they should be interchangeable. Specifying size at compile time can only improve performance.
You could implement your suggestion by replacing std::vector in the given implementation with std::array/boost::array. If the template parameter is only used to define a runtime parameter, nothing is gained.
i.e. vector spaces of varying dimension
If the dimension is not known at compile time, it can't be a template parameter. Period.
Templates are more powerful at compile time, but at the cost of some flexibility at runtime.
Related
I am quite new to c++ and I try to create an Array class in c++17 with the use of templates. In this class I overload the + operator, in such a way that it can add Arrays of multiple types. It does work so far and I am able to add arrays of different e.g. float and int type together. However, I am having some trouble with how to define the type of the new array, which is the result of the addition.
Let's say the arrays which I add are of type float and int. Then the new array should also be float. However, on forehand I dont know which array has the float type, the first one or the second one, so I can't create a new array with typename T or U.
Also, if due to coindicdence two float arrays add up together to only int values (e.g. 1.5 + 3.5 = 5(int) ), then the new array should be of type int.
Basically in summary, I try to define the type of the new array based on the type of the content after addition.
I came across some solutions that include decltype. However I can't manage to find a way how to include this for multiple values, since the array has more than one value. In my current code I create the new array based on the type T. However, if in a case T is of type int and U of type float, the result is not correct.
Any advice or tips are much appreciated.
Thanks in advance,
template <typename T>
class Array {
public:
T* content;
int length;
// Default Constructor
Array() : content(nullptr), length(0) {}
// Constructor when length is provided
Array(int length) : content(new T[length]), length(length) {}
// Constructor (using initializer list)
Array(std::initializer_list<T> list) : Array((int)list.size()) {
std::uninitialized_copy(list.begin(), list.end(), content);
}
// Obtain content at index i
float& operator[](int i) { return content[i]; }
// Adding arrays
template <typename U>
Array& operator+(Array<U>& other) {
Array<T>* new_array = new Array(other.length);
for (auto i = 0; i < other.length; i++)
new_array->content[i] = this->content[i] + other.content[i];
return *new_array;
}
};
With decltype, your operator + might look like:
template<typename U>
auto operator+(const Array<U>& rhs)
-> Array<std::decay_t<decltype((*this)[0] + rhs[0])>>
{
Array<std::decay_t<decltype((*this)[0] + rhs[0])>> res(rhs.length);
for (auto i = 0; i != rhs.length; i++) {
res[i] = (*this)[i] + rhs[i];
}
return res;
}
Demo
Toy example:
template<typename T, std::size_t N>
class static_vector
{
public:
T& operator[](std::size_t i) { return m_elements[i]; }
T const& operator[](std::size_t i) const { return m_elements[i]; }
private:
std::array<T, N> m_elements;
};
template<typename T>
class vector3
: public static_vector<T, 3>
{
public:
using vector_type = static_vector<T, 3>;
// x = vector_type::operator[](0);
// y = vector_type::operator[](1);
// z = vector_type::operator[](2);
};
Let vector3<float> pos;. I want to access pos[0] via pos.x. Clearly, if pos is declared to be const, I want pos.x to be read-only.
Is this possible?
Let me stress the fact that I don't want to use accessor functions of the form
T& x() { return (*this)[0]; }
T const& x() const { return (*this)[0]; }
There is no zero cost way to do this using the exact syntax you want.
Relaxing either cost (compile, maintenance, memory usage and runtime) or syntax (which your () is an example of) gets you what you want.
I added a comment to your question but I thought I'd add an answer with some code to clarify. Be warned, what follows is not a good idea.
You can use simple pointer arithmetic to interpret members of a struct as if they were elements in an array. Because the type of the struct members and the type of elements in the pseudo array are the same, we're safe to reinterpret one as the other with the caveat that there is no padding in between the struct members.
The C++ standard gives no method for defining padding in a struct so you will have to rely on compiler specific directives. I believe however that both MSVC and GCC support #pragma pack.
#pragma pack(push, 1)
template <typename T>
struct Vec3
{
T x;
T y;
T z;
T& operator[](size_t i) { return *(&x + i); }
const T& operator[](size_t i) const { return *(&x + i); }
};
#pragma pack(pop)
So why isn't this a good solution?
You are relying on compiler specific directives making your code less portable.
You need to explicitly declare each member which means you'll need separate templates for Vec2, Vec3 and Vec4.
1 byte alignment isn't supported on all architectures again making your code less portable.
Even on architectures where unaligned memory access is supported (such as x86,) it comes with a performance penalty.
I'm writing a class for Hermitian matrices. This is a complex matrix that has only n*(n+1)/2 independent complex numbers (ignoring details about the diagonal being exactly real).
My plan is to write only the upper triangular elements, where row number compared to column number satisfy the condition satisfy the rule: row >= column. However, this requires something like a proxy? I'm not sure how to implement this. Here's the problem:
Say I implement the member function at(int row, int column) to access an element.
template<typename T>
std::complex<T>& HermitianMatrix<T>::at(long row, long column)
{
if(row >= column)
return this->_matrix[ElementIndex(row,column)];
else
return std::conj(this->_matrix[ElementIndex(column,row)]);
}
where ElementIndex converts the row and column input to the the position in the array std::complex<T>* _matrix = new std::complex<T>(...). Of course, this method returns a reference. The code you see above doesn't work for the lower triangular part of the matrix because the reference is gone after returning.
What is the right and most efficient way to implement this, such that I have some kind of "pipe" for the lower triangular matrix part always goes through std::conj for both set and get?
Please ask for more information if required. Thank you.
Following the Franck's example, I propose to return a wrapper class (or struct) that wrap the reference to the element and memorize a boolean flag to remember if it's neccessary to coniugate the number.
Something like [caution: not tested]
template <typename T>
struct cWrapper
{
bool c;
std::complex<T> & r;
cWrapper (bool c0, std::complex<T> & r0) : c{c0}, r{r0}
{ }
operator std::complex<T>() const
{ return c ? std::conj(r) : r; }
cWrapper & operator= (const std::complex<T> & r0)
{
r = ( c ? std::conj(r0) : r0 );
return *this;
}
};
and your function could become [edit: modified after the corresponding edit in the question (row/column inversion for else case)]
template<typename T>
cWrapper<T> HermitianMatrix<T>::at(long row, long column)
{
if(row >= column)
return cWrapper<T>(false, this->_matrix[ElementIndex(row,column)]);
else
return cWrapper<T>(true, this->_matrix[ElementIndex(column,row)]);
}
You can implement a property class and return an object of this class.
template <typename T>
struct ComplexGetter {
std::complex<T>* ref;
std::complex<T> conj;
ComplexGetter(std::complex<T>& reference) : ref(&reference) {}
ComplexGetter(const std::complex<T>& conjugate) : ref(nullptr), conj(conjugate) {}
operator std::complex<T>() const { return ref ? *ref : conj; }
operator=(const std::complex<T>& source)
{ if (ref) *ref = source;
else { ... /* do something */ }
}
};
It can be assigned and automatically converted.
Considering that std::conj() doesn't return a reference, you have two options:
do not return a reference in your function, but a value
implement your own version of std::conj() function which returns a reference
I have an existing class, which is structured in the following way:
class Matrix
{
public:
float Data[4][4];
// ... methods
};
And subsequently used in the following ways:
Matrix m;
m.Data[0][0] = 1.0f;
float local = m.Data[0][0];
//...
I would like to replace the Data member with an overloaded indexing operator, so I can perform range checking on the indices used. While I can change the Matrix class itself, and the implementations of its member functions, I cannot modify its usages in existing code, so any solution requires that the usage syntax remains identical. It's also desirable that the solution doesn't change sizeof(Matrix). Is there a way to achieve this?
Generally for this sort of thing, you need to use a proxy class to handle the second indexing operator. It would look something like this and go in the private section of your Matrix class. I'll leave out the bounds-checking (it shouldn't be hard for you to add that yourself).
class Proxy {
Matrix& ref;
size_t i;
public:
Proxy(Matrix& on, size_t i) : ref(on), i(i) {}
float operator[] (size_t j) {
return ref.Data[i][j];
}
};
Then just have your Matrix::operator[] return an instance of this class:
Proxy operator[] (size_t i) {
return Proxy(*this, i);
}
Note that if you want a const overload (ie, you want to use the indexing operator on const Matrix objects), you'll need a separate ConstProxy class which has const Matrix& ref instead of Matrix& ref but is otherwise identical.
There is also the option of returning a reference to an array. (Note: as one of the comments pointed out, this doesn't help much with bound-checking, but I think it's interesting, so I'll leave it here.)
float (&operator[](size_t i))[4] {
return Data[i];
}
The syntax for that is quite arcane, and I believe it doesn't work in Visual Studio 2013, but you can make it a bit cleaner with a typedef.
using Proxy = float[4];
Proxy& operator[](size_t i) {
return Data[i];
}
There's one more option, if you don't mind abandoning square-bracket indexing. You can overload the function call operator like this:
float operator()(size_t i, size_t j) {
return Data[i][j];
}
Another way is define a the proxy class with the semantic of a vector
class Matrix
{
public:
struct SubMatrix
{
class Vector
{
public:
Vector(float *data) : Data(data) {}
float &operator[](int index) { return Data[index]; }
private:
float *Data;
};
Vector operator[](int index)
{
return Vector(Data[index]);
}
float Data[4][4];
};
SubMatrix Data;
// ... methods
};
Then you can use it this way:
Matrix m;
float f = m.Data[1][2];
I am writing a template Polynom<T> class where T is the numeric type of its coefficients.
The coefficients of the polynom are stored in an std::vector<T> coefficients, where coefficients[i] corresponds to x^i in a real polynom. (so the powers of x are in increasing order).
It is guaranteed that coefficients vector always contains at least one element. - for a zero polynom it is T().
I want to overload the operator[] to do the following:
The index passed to the operator[] corresponds to the power of X whose coefficient we want to modify / read.
If the user wants to just read the coefficient, it should throw for negative indices, return coefficients.at(i) for indices within the stored range - and reasonably return 0 for all other indices, not throw.
If the user wants to modify the coefficient, it should throw for negative indices, but let user modify all other indices freely, even if the index specified is bigger than or equal to coefficients.size(). So we want to somehow resize the vector.
The main problem I have collided with is as follows:
1.
How do I distinguish between the read case and the write case? One person left me without an explanation but said that writing two versions:
const T& operator[] (int index) const;
T& operator[] (int index);
was insufficient. However, I thought that the compiler would prefer the const version in the read case, won't it?
2.
I want to make sure that no trailing zeros are ever stored in the coefficients vector. So I somehow have to know in advance, "before" I return a mutable T& of my coefficient, what value user wants to assign. And I know that operator[] doesn't receive a second argument.
Obviously, if this value is not zero (not T()), then I have to resize my vector and set the appropriate coefficient to the value passed.
But I cannot do it in advance (before returning a T& from operator[]), because if the value to be assigned is T(), then, provided I resize my coefficients vector in advance, it will eventually have lots of trailing "zeroes".
Of course I can check for trailing zeroes in every other function of the class and remove them in that case. Seems a very weird decision to me, and I want every function to start working in assumption that there are no zeroes at the end of the vector if its size > 1.
Could you please advise me as concrete solution as possible to this problem?
I heard something about writing an inner class implicitly convertible to T& with overloaded operator=, but I lack the details.
Thank you very much in advance!
One option you could try (I haven't tested this):
template<typename T>
class MyRef{
private:
int index;
Polynom<T>*p;
public:
MyRef(int index, Polynom<T>*p) : index(index), p(p) { }
MyRef<T>& operator=(T const&t); //and define these appropriately
T operator T() const;
};
and define:
MyRef<T> operator[](int index){
return MyRef<T>(index, this);
}
This way when you assign a value to the "reference" it should have access to all the needed data in the polynomial, and take the appropriate actions.
I am not familiar enough with your implementation, so I'll instead give an example of a very simple dynamic array that works as follows:
you can read from any int index without concern; elements not previously written to should read off as 0;
when you write to an element past the end of the currently allocated array, it is reallocated, and the newly allocated elements are initialized to 0.
#include <cstdlib>
#include <iostream>
using namespace std;
template<typename T>
class my_array{
private:
T* _data;
int _size;
class my_ref{
private:
int index;
T*& obj;
int&size;
public:
my_ref(T*& obj, int&size, int index)
: index(index), obj(obj), size(size){}
my_ref& operator=(T const& t){
if (index>=size){
obj = (T*)realloc(obj, sizeof(T)*(index+1) );
while (size<=index)
obj[size++]=0;
}
obj[index] = t;
return *this;
}
//edit:this one should allow writing, say, v[1]=v[2]=v[3]=4;
my_ref& operator=(const my_ref&r){
operator=( (T) r);
return *this;
}
operator T() const{
return (index>=size)?0:obj[index];
}
};
public:
my_array() : _data(NULL), _size(0) {}
my_ref operator[](int index){
return my_ref(_data,_size,index);
}
int size() const{ return _size; }
};
int main(){
my_array<int> v;
v[0] = 42;
v[1] = 51;
v[5] = 5; v[5]=6;
v[30] = 18;
v[2] = v[1]+v[5];
v[4] = v[8]+v[1048576]+v[5]+1000;
cout << "allocated elements: " << v.size() << endl;
for (int i=0;i<31;i++)
cout << v[i] << " " << endl;
return 0;
}
It's a very simple example and not very efficient in its current form but it should prove the point.
Eventually you might want to overload operator& to allow things like *(&v[0] + 5) = 42; to work properly. For this example, you could have that operator& gives a my_pointer which defines operator+ to do arithmetic on its index field and return a new my_pointer. Finally, you can overload operator*() to go back to a my_ref.
The solution to this is a proxy class (untested code follows):
template<typename T> class Polynom
{
public:
class IndexProxy;
friend class IndexProxy;
IndexProxy operator[](int);
T operator[](int) const;
// ...
private:
std::vector<T> coefficients;
};
template<typename T> class Polynom<T>::IndexProxy
{
public:
friend class Polynom<T>;
// contrary to convention this assignment does not return an lvalue,
// in order to be able to avoid extending the vector on assignment of 0.0
T operator=(T const& t)
{
if (theIndex >= thePolynom.coefficients.size())
thePolynom.coefficients.resize(theIndex+1);
thePolynom.coefficients[theIndex] = t;
// the assignment might have made the polynom shorter
// by assigning 0 to the top-most coefficient
while (thePolynom.coefficients.back() == T())
thePolynom.coefficients.pop_back();
return t;
}
operator T() const
{
if (theIndex >= thePolynom.coefficients.size())
return 0;
return thePolynom.coefficients[theIndex];
}
private:
IndexProxy(Polynom<T>& p, int i): thePolynom(p), theIndex(i) {}
Polynom<T>& thePolynom;
int theIndex;
}
template<typename T>
Polynom<T>::IndexProxy operator[](int i)
{
if (i < 0) throw whatever;
return IndexProxy(*this, i);
}
template<typename T>
T operator[](int i)
{
if (i<0) throw whatever;
if (i >= coefficients.size()) return T();
return coefficients[i];
}
Obviously the code above is not optimized (especially the assignment operator has clearly room for optimization).
You cannot distinguish between read and write with operator overloads. The best you can do is distinguish between usage in a const setting and a non-const setting, which is what your code snippet does. So:
Polynomial &poly = ...;
poly[i] = 10; // Calls non-const version
int x = poly[i]; // Calls non-const version
const Polynomial &poly = ...;
poly[i] = 10; // Compiler error!
int x = poly[i] // Calls const version
It sounds like the answer to both your questions, therefore, is to have separate set and get functions.
I see two solutions to your problem:
Instead of storing the coefficients in a std::vector<T> store them in a std::map<unsigned int, T>. This way you will ever only store non-zero coefficients. You could create your own std::map-based container that would consume zeros stored into it. This way you also save some storage for polynomials of the form x^n with large n.
Add an inner class that will store an index (power) and coefficient value. You would return a reference to an instance of this inner class from operator[]. The inner class would overwrite operator=. In the overridden operator= you would take the index (power) and coefficient stored in inner class instance and flush them to the std::vector where you store your coefficients.
This is not possible. The only way I can think of is to provide a special member-function for adding new coefficients.
The compiler decides between the const and non-const version by looking at the type of Polynom, and not by checking what kind of operation is performed on the return-value.