Suppose we want two constructors for a class representing complex numbers:
Complex (double re, double img) // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates
but the parameters (number and type) are the same: what is the more elegant way
to identify what is intended? Adding a third parameter to one of the constructors?
It is better to add static methods with appropriate names and let them to create the objects.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
You can't have two constructors (or any functions) with the same signatures. The best solution is probably to create classes for your coordinate types and overload on those. For example:
struct CartCoord {
CartCoord( double re, double img ) : mRe(re), mImg(img) {}
double mRe, mImg;
};
struct PolarCoord {
PolarCoord( double a, double v ) : mA(a), mV(v) {}
double mA, mV;
};
Then your constructors become:
Complex( const CartCoord & c );
Complex( const PolarCoord & c);
In use:
Complex c( CartCoord( 1, 2 ) );
You can also use them with overloaded operators of the Complex class. For example, assuming you have a binary + operator for the class define as:
Complex operator+( const Complex &, const Complex & );
then:
Complex a( CartCoord( 0, 0 ) );
Complex b = a + PolarCoord( 1, 1 );
As we have a conversion constructor from PolarCoord to Complex, this will be used in the + expression. This is more natural (IMHO) than calling static functions to create the temporary..
This is an example of Koenig's dictum (or at least a version of it) - whenever faced with a difficult problem, introduce a new level of classes to solve it.
Use the named constructor idiom described here at the Parashift C++ FAQ.
You can't - if the method signatures are the same, you're stuffed.
Of course, you could always create a subclass for each type of coordinate system, but that's far from ideal - especially if you later find a good reason to want to subclass Complex for other reasons...
Instead of having two constructors, you need to have only one, but add a third parameter, for example:
Complex (double re, double img, enum type) {
if(type == polar) {
..treat as polar coordinates..
} else {
..treat as cartesian coordinates..
}
}
'enum type' can have a default type as well so you don't have to supply what type of coordinates you intend to use every time, the default should off course be what's most used.
Complex (double re, double img, enum type = polar);
Since no one mentioned it, you can use tags:
class Complex{
struct CartCoord{};
struct PolarCoord{};
Complex( CartCoord, double re, double img);
Complex( PolarCoord, double a, double v);
};
int main(){
auto c1 = Complex(Complex::CartCoord{}, 5, 6);
auto c2 = Complex(Complex::PolarCoord{}, 5, 6);
}
I don't know if it is good practice in C++ but I would name these two methods differently, at least for a maintainability point of view.
I would probably create more classes, but then I am an adept of Boost Strong Typedef library.
For me it does not make sense to use double to represent both coordinates, module and angles.
So I would have:
class CoordinateX {};
class CoordinateY {};
class Modulus {};
class Angle {};
class Complex
{
public:
Complex(CoordinateX, CoordinateY);
Complex(Modulus, Angle);
};
And there it's perfectly clear, and there is no ambiguity. Also you add some compile-time check of "units" in a loose sense. It rarely makes sense (if ever) to add an X-coordinate and an Y-coordinate, or worse a distance and an angle.
For me the more elegant way would be to create a class representing cartesian coordinates and another representing polar coordinates, then give object of the relevant class to the constructors.
That way you would have two constructor using different parameters.
I use this simple alternative way while practicing C++, I don't know if it is what you want.
class Vector{
public:
float x, y;
Vector();
Vector(float , float, bool);
float get_distance(Vector v); // find distance from another vector
float get_magnitude(); // find distance from origin point
Vector add(Vector v);
Vector subtract(Vector v);
Vector multiply(Vector v); // multiply by vector
Vector multiply(float scalar); // multiply by scalar
float get_angle();
};
Vector::Vector(float a, float b, bool is_cartesian = true){
if(is_cartesian){
x = a;
y = b;
}
else{
x = a * cos( b );
y = a * sin( b );
}
}
Related
I have a function which calculates the first derivative dy/dx for discrete values y(x) stroed as std::vector:
vector<double> CalcDerivative(vector<double>&y, vector<double>&x) {...}
Often the spacing dx is constant so it would be more efficient to pass a double to this function instead of vector<double> as argument x.
I tried to accomplish this with std::variant. The drawback with std::variant is however, that it cannot handle references so the vector x has to be copied while being passed as a variant to the function.
For now I solved the problem by defining two functions with overloaded arguments. But I wonder whether there is a more elegant solution which won't duplicate the code for the two cases (x as double or as vector<double>).
One possible solution might be to define the "worker" function such that it is independent of the "number of passed doubles". For this purpose, std::span is suitable. The exemplary solution might look like:
std::vector<double> CalcDWorker(
std::span<const double> y, std::span<const double> x)
{
... // x.size() == 1 indicates uniform spacing
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, const std::vector<double>& x)
{
return CaclDWorker({y.begin(), y.end()}, {x.begin(), x.end()});
}
std::vector<double> CalcDerivative(
const std::vector<double>& y, double x)
{
return CaclDWorker({y.begin(), y.end()}, {&x, 1});
}
It requires C++20, but there are third-party span implementations available also for earlier C++ versions (such as the one provided by Boost).
Live demo: https://godbolt.org/z/n6adEKWes
I'm only beginning in C++ and I'm struggling to understand some code from a custom vector class in an article I'm working through. The author writes it as:
class vec3
{
public:
vec3() {}
vec3(float e0, float e1, float e2)
{
e[0] = e0;
e[1] = e1;
e[2] = e2;
}
(...)
But so far I've only seen class definitions where the types of data it holds are defined, such as:
class vec3
{
public:
float m_x;
float m_y;
float m_z;
vec3(float x, float y, float z) : m_x(x), m_y(y), m_z(z)
{}
My guess was that the code in the article is creating an empty vector which it then populates with floats or there was something assumed in the definition. Is this just a syntax difference or is there something more fundamental that I'm missing? Apologies for what seems like a basic question but I couldn't find any similar questions. . . it might be too basic for that! But I just wanted to understand it before I moved on.
Thanks,
Paddy
In the code you've posted, you are correct that there is no declaration for the variable e anywhere. I'm not sure if this is because you didn't post that part of the code from the book, or if the book omitted that for brevity.
Without knowing what the book author was meaning by e, I don't want to suggest a completion of the code. There are several things that e could be declared as that would be compatible with the code you've posted.
It defines e as just a float array [e[3]].
With this information added, then there is no relevant difference between three separate members and an array. In the end, both variants will require the same amount of memory, and in most cases, the (optimised!) code generated by the compiler will be exactly the same:
float getY()
{
return m_y;
// will result in address of object + offset to m_y
}
float getY()
{
return e[1];
// will result in address of object + offset to e + offset to second element
// as both offsets are constant, they will be joined to one single summand
// and we are back at first variant...
}
One of the few things you can do with arrays but not with separate members is having a loop, such as the following:
float magnitude()
{
float sum = 0.0F;
for(auto f : e)
sum += f*f;
return sqrtf(sum);
}
However, for such short loops, loop unrolling is pretty likely, and the code generated again is with high probability equivalent to the separate member variant:
float magnitude()
{
return sqrtf(m_x * m_x + m_y * m_y + m_z * m_z);
}
With an array, you could pass all three members in one single parameter to other functions (as pointer to first element), with separate members, you'd have to pass all of them separately (well, there are ways around, but they either require extra effort or are "dirty"...).
I'm revamping an old application that use Numerical Recipes' dmatrix quite extensively. Since one of the reasons I'm working on the application is because its code is about to be opened, I want to replace all of the Numerical Recipes code with code that can be freely distributed.
dmatrix is a function that returns a matrix of doubles. The called supplies the lower and upper bound for each index, like so:
double **mat = dmatrix(1,3,1,3);
mat now has 3 rows, from 1 to 3, and 3 columns, from 1 to 3, so that mat[1][1] is the first element and mat[3][3] is the last.
I looked at various C++ matrix implementations, none of them allowed me to specify the lower bound of each dimension. Is there something I can use, or do I have to write yet another matrix class for this?
I believe that you can easily make a wrapper of some other matrix implementation to add the lower bound feature. Example (untested):
class Matrix {
OtherMatrix m;
int lowerX, lowerY;
public:
Matrix(int lx, int hx, int ly, int hy) :
m(hx-lx, hy-ly),
lowerX(lx), lowerY(ly) { }
MatrixCol operator[] (int x) {
return {this, x};
}
};
class MatrixCol {
friend class Matrix;
Matrix* mm;
int x;
public:
double& operator[] (int y) {
return mm->m[x - mm->lowerX, y - mm->lowerY];
}
};
This may require a little more robust implementation depending on your use case. But this is the basic idea, expand from it.
OK, I've been googling around for too long, I'm just not sure what to call this technique, so I figured it's better to just ask here on SO. Please point me in the right direction if this has an obvious name and/or solution I've overlooked.
For the laymen: a tensor is the logical extension of the matrix, in the same way a matrix is the logical extension of the vector. A vector is a rank-1 tensor (in programming terms, a 1D array of numbers), a matrix is a rank-2 tensor (a 2D array of numbers), and a rank-N tensor is then simply an N-D array of numbers.
Now, suppose I have something like this Tensor class:
template<typename T = double> // possibly also with size parameters
class Tensor
{
private:
T *M; // Tensor data (C-array)
// alternatively, std::vector<T> *M
// or std::array<T> *M
// etc., or possibly their constant-sized versions
// using Tensor<>'s template parameters
public:
... // insert trivial fluffy stuff here
// read elements
const T & operator() (size_t a, size_t b) const {
... // error checks etc.
return M[a + rows*b];
}
// write elements
T & operator() (size_t a, size_t b) {
... // error checks etc.
return M[a + rows*b];
}
...
};
With these definitions of operator()(...), indexing/assign individual elements then has the same call signature:
Tensor<> B(5,5);
double a = B(3,4); // operator() (size_t,size_t) used to both GET elements
B(3,4) = 5.5; // and SET elements
It is fairly trivial to extend this up to arbitrary tensor rank. But what I'd like to be able to implement is a more high-level way of indexing/assigning elements:
Tensor<> B(5,5);
Tensor<> C = B( Slice(0,4,2), 2 ); // operator() (Slice(),size_t) used to GET elements
B( Slice(0,4,2), 2 ) = C; // and SET elements
// (C is another tensor of the correct dimensions)
I am aware that std::valarray (and many others for that matter) does a very similar thing already, but it's not my objective to just accomplish the behavior; my objective here is to learn how to elegantly, efficiently and safely add the following functionality to my Tensor<> class:
// Indexing/assigning with Tensor<bool>
B( B>0 ) += 1.0;
// Indexing/assigning arbitrary amount of dimensions, each dimension indexed
// with either Tensor<bool>, size_t, Tensor<size_t>, or Slice()
B( Slice(0,2,FINAL), 3, Slice(0,3,FINAL), 4 ) = C;
// double indexing/assignment operation
B(3, Slice(0,4,FINAL))(mask) = C; // [mask] == Tensor<bool>
.. etc.
Note that it's my intention to use operator[] for non-checked versions of operator(). Alternatively, I'll stick more to the std::vector<> approach of using .at() methods for checked versions of operator[]. Anyway, this is a design choice and besides the issue right now.
I've conjured up the following incomplete "solution". This method is only really manageable for vectors/matrices (rank-1 or rank-2 tensors), and has many undesirable side-effects:
// define a simple slice class
Slice ()
{
private:
size_t
start, stride, end;
public:
Slice(size_t s, size_t e) : start(s), stride(1), end(e) {}
Slice(size_t s, size_t S, size_t e) : start(s), stride(S), end(e) {}
...
};
template<typename T = double>
class Tensor
{
... // same as before
public:
// define two operators() for use with slices:
// version for retrieving data
const Tensor<T> & operator() (Slice r, size_t c) const {
// use slicing logic to construct return tensor
...
return M;
{
// version for assigning data
Sass operator() (Slice r, size_t c) {
// returns Sass object, defined below
return Sass(*this, r,c);
}
protected:
class Sass
{
friend class Tensor<T>;
private:
Tensor<T>& M;
const Slice &R;
const size_t c;
public:
Sass(Tensor<T> &M, const Slice &R, const size_t c)
: M(M)
, R(R)
, c(c)
{}
operator Tensor<T>() const { return M; }
Tensor<T> & operator= (const Tensor<T> &M2) {
// use R/c to copy contents of M2 into M using the same
// Slice-logic as in "Tensor<T>::operator()(...) const" above
...
return M;
}
};
But this just feels wrong...
For each of the indexing/assignment methods outlined above, I'd have to define a separate Tensor<T>::Sass::Sass(...) constructor, a new Tensor<T>::Sass::operator=(...), and a new Tensor<T>::operator()(...) for each and every such operation. Moreover, the Tensor<T>::Sass::operators=(...) would need to contain much of the same stuff that's already in the corresponding Tensor<T>::operator()(...), and making everything suitable for a Tensor<> of arbitrary rank makes this approach quite ugly, way too verbose and more importantly, completely unmanageable.
So, I'm under the impression there is a much more effective approach to all this.
Any suggestions?
First of all I'd like to point out some design issues:
T & operator() (size_t a, size_t b) const;
suggests you can't alter the matrix through this method, because it's const. But you are giving back a nonconst reference to a matrix element, so in fact you can alter it. This only compiles because of the raw pointer you are using. I suggest to use std::vector instead, which does the memory management for you and will give you an error because vector's const version of operator[] gives a const reference like it should.
Regarding your actual question, I am not sure what the parameters of the Slice constructor should do, nor what a Sass object is meant to be (I am no native speaker, and "Sass" gives me only one translation in the dictionary, meaning sth. like "impudence", "impertinence").
However, I suppose with a slice you want to create an object that gives access to a subset of a matrix, defined by the slice's parameters.
I would advice against using operator() for every way to access the matrix. op() with two indices to access a given element seems natural. Using a similar operator to get a whole matrix to me seems less intuitive.
Here's an idea: make a Slice class that holds a reference to a Matrix and the necessary parameters that define which part of the Matrix is represented by the Slice. That way a Slice would be something like a proxy to the Matrix subset it defines, similar to a pair of iterators which can be seen as a proxy to a subrange of the container they are pointing to. Give your Matrix a pair of slice() methods (const and nonconst) that give back a Slice/ConstSlice, referencing the Matrix you call the method on. That way, you can even put checks into the method to see if the Slice's parameters make sense for the Matrix it refers to. If it makes sense and is necessary, you can also add a conversion operator, to convert a Slice into a Matrix of its own.
Overloading operator() again and again and using the parameters as a mask, as linear indices and other stuff is more confusing than helping imo. operator() is slick if it does something natural which everybody expects from it. It only obfuscates the code if it is used everywhere. Use named methods instead.
Not an answer, just a note to follow up my comment:
Tensor<bool> T(false);
// T (whatever its rank) contains all false
auto lazy = T(Slice(0,4,2));
// if I use lazy here, it will be all false
T = true;
// now T contains all true
// if I use lazy here, it will be all true
This may be what you want, or it might be unexpected.
In general, this can work cleanly with immutable tensors, but allowing mutation gives the same class of problem as COW strings.
If you allow for your Tensor to implicitly be a double you can return only Tensors from your operator() overload.
operator double() {
return M.size() == 1 ? M[0] : std::numeric_limits<double>::quiet_NaN();
};
That should allow for
double a = B(3,4);
Tensor<> a = B(Slice(1,2,3),4);
To get the operator() to work with multiple overloads with Slice and integer is another issue. I'd probably just use Slice and create another implicit conversion so integers can be Slice's, then maybe using the variable argument elipses.
const Tensor<T> & operator() (int numOfDimensions, ...)
Although the variable argument route is kind of a kludge best to just have 8 specializations for 1-8 parameters of Slice.
I have the following functor for redefining the less operator of the sort method for the vector type:
typedef vector< vector<int> > MxInt2d;
typedef vector< vector<double> > MxDouble2d;
class QSweep{
public:
....
static MxDouble2d myPoints_;
MxDouble2d myEdges_;
class order{
public:
bool operator() (const vector<int>& edge1, const vector<int>& edge2){
//std::cout<<"inside sort"<<endl;
//3 sort criteria
return (myPoints_[edge1[0]][0]<myPoints_[edge2[0]][0])||
(myPoints_[edge1[0]][0]==myPoints_[edge2[0]][0]&&
myPoints_[edge1[0]][1]<myPoints_[edge2[0]][1])
||
(myPoints_[edge1[0]][0]==myPoints_[edge2[0]][0]&&
myPoints_[edge1[0]][1]==myPoints_[edge2[0]][1]&&
getSlope(myPoints_[edge1[0]][0],myPoints_[edge1[0][1],
myPoints_[edge1[1]][0],myPoints_[edge1[1]][0])
<
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][0]));
}
};
static double getSlope(double a, double b, double c, double d);
};
where getSlope is a function defined in the following way:
double QSweep::getSlope(double a, double b, double c, double d){
double slope=0.0;
//std::cout<<"slope criteria"<<endl;
double denum=c-a;
if (denum==0){
std::cout<<"zero denominator"<<endl;
}
else{
slope=(d-b)/denum;
}
return slope;
}
Each point is given by an index, an x, and a y coordinate; Each edge is given by source-edge[0] and destination-edge[1],where edge[0],edge[1] are indexes of the points).
I want to arrange the edge:
- by the x coordinate of their edge[0] coordinate (iff the x's of 2 edges are different)
- by the y coordinate of their edge[0] coordinate (iff the x's of 2 edges are equal)
- by their corresponding slopes (iff the x's of edges and the y's of edges are equal).
I declared the getSLope function static, but when I sort the edges with
sort(myEdges_.begin(),myEdges_.end(),order());
the last condition is not fullfilled.
if I have two edges with the same x's and y's for edgep[0] but with different slopes, e.g. slope(edge1)=1 ,slope(edge2)=1/2 than I would want to get
[edge2, edge1]; instead I get [edge1,edge2].
So my getSlope criteria is not computed.
is it because I declared getSlope static? what should I change so that the criteria is fulfilled?
thank you in advance for your suggestions,
madalina
crikey! It looks quite complex, firstly have you tried with a less complex set of values to compute - ie I see you have cout statements, I trust that they work correctly when you run it?
If so, can iut be that your inputs to getSlope are wrong - shouldn't
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][0])
be
getSlope(myPoints_[edge2[0][0],myPoints_[edge2[0][1],
myPoints_[edge2[1]][0],myPoints_[edge2[1]][1])
Maybe it happened because expression result could be calculated without it.
E.g.:
false && someFunction(); - function will not be called
true || someFunction(); - function will not be called
This is nice rule, it allow us write next:
if ( ptr && ptr->someMethod() )
// call method will not be called for NULL pointers