I've got this piece of code for a class (this is a snippet):
template<typename T>
class Pos2 {
public:
T x, y;
Pos2() : x(0), y(0) {};
Pos2(T xy) : x(xy), y(xy) {};
Pos2(T x, T y) : x(x), y(y) {};
};
Now, I've also got 2 typedefs for it:
typedef Pos2<pos_scalar> Pos;
typedef Pos2<size_scalar> Size;
Everything works as expected, but when I do this:
Pos p(5.5, 6.5);
Size s(3, 8);
p = s;
I get this error:
error: conversion from ‘Size {aka Pos2<short int>}’ to non-scalar type ‘Pos’ requested
It makes sense, but I'd like to know how to fix it =P
Add a constructor
template <typename Type2> Pos2(const Pos2<Type2> &other)
{ x = other.x; y = other.y; }
You need to define an assignment operator for assignment from type Size to type Pos, because these are not the same type and therefore there is no default assignment operator between the two.
I guess you want to use a template here, so any instantiation of Pos2 can be used to assign to another instantiation. For example like so:
template<typename T>
class Pos2 {
public:
T x, y;
Pos2() : x(0), y(0) {};
Pos2(T xy) : x(xy), y(xy) {};
Pos2(T x, T y) : x(x), y(y) {};
template<typename FromT>
Pos2<T>& operator=(const Pos2<FromT>& from) {
x = from.x;
y = from.y;
return *this;
}
};
You should do the same with the copy constructor (not shown here), because it might likely happen that you want to copy construct in the same scheme at some point.
This does only work if the assignment between type T and FromT, that is pos_scalar and size_scalar is possible. If not try to add correct explicit conversions and/or template specializations for the assignment operator.
Also if any of the members of Pos2 are private/protected you will need to friend the assignment operator or provide adequate getters.
Related
Supposed I have a class like this:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), x(b) {}
T x;
T y;
}
I want to be able to do something like this:
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
// i.x == 31
// i.y == 48
I have tried overloading a generic operator but it seems to break when trying to convert from a const value. Help?
Provide an additional constructor that's taking another template parameter U:
template<class T>
class Vector2 {
public:
template <class U>
Vector2(const Vector2<U> & other) : x(other.x), y(other.y){}
// other code ommited
};
After all, you're trying to use Vector2<T>::Vector2(const Vector2<U> &), where U = double and T = int.
Note that this has nothing to do with your original vector being const. Instead, you're trying to construct a value of type Vector2<int> with a value of another type Value2<double>. Those are distinct types, and therefore you need to provide a constructor.
A possibility would be to write a cast operator which does what you want:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), y(b) {}
T x;
T y;
template<typename U>
operator Vector2<U>() const { return Vector2<U>( (U)x, (U)y ); }
// ^^^^^^^^ cast operator
};
int main()
{
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
return 0;
}
An additional constructor as shown in the answer of Zeta is the much more elegant solution.
Why can I not check two objects of classes with explicit constructor only for equality? The following code does not compile
struct Foo
{
explicit Foo(int x) : x_(x) {}
int x_;
};
int main()
{
Foo(1) == Foo(1);
}
Do I have to declare operator == explicitly?
You need to overload the equality operator==:
struct Foo {
explicit Foo(int x) : x_(x) {}
int x_;
};
bool operator==(Foo const &lhs, Foo const& rhs) { return lhs.x_ == rhs.x_; }
LIVE DEMO
How shoud compiler know how it should compare them? Either define operator== or use Foo(1).x_ == Foo(1).x_ if you want to compare those ints.
Maybe you misunderstood what explicit constructor means. It's about asignment operator = and not comparism. Marking your constructor explicits disables following snippet to compile: Foo f = 1.
Yes, the compiler does not generate equality for you, so you have to do it yourself. This isn't about explicit constructors either; at no point has C++ ever allowed comparing classes or structs implicitly.
You need an operator == like that:
bool operator==(const Foo& f) { return x_==f.x_; }
This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 7 years ago.
I am making program in which I create class for vector and overload different operators. Now I want to make arguments of vector (coordinates) as templates.
When I have all code in one file everything is alright and program is running correctly:
#ifndef VECTOR4D_H_INCLUDED
#define VECTOR4D_H_INCLUDED
template <typename TYPE>
class VECTOR4D{
public:
VECTOR4D (void): X(0), Y(0), Z(0), T(0){};
VECTOR4D (TYPE X, TYPE Y, TYPE Z, TYPE T): X(X), Y(Y), Z(Z), T(T){};
TYPE X, Y, Z, T;
VECTOR4D &operator+=(VECTOR4D &K){
this->X += K.X;
this->Y += K.Y;
this->Z += K.Z;
this->T += K.T;
return *this;
}
};
#endif // VECTOR4D_H_INCLUDED
but when I separate implementation and declaration of overload operator I have a problem.
//vector4d.h
#ifndef VECTOR4D_H_INCLUDED
#define VECTOR4D_H_INCLUDED
template <typename TYPE>
class VECTOR4D{
public:
VECTOR4D (void): X(0), Y(0), Z(0), T(0){};
VECTOR4D (TYPE X, TYPE Y, TYPE Z, TYPE T): X(X), Y(Y), Z(Z), T(T){};
TYPE X, Y, Z, T;
VECTOR4D &operator+=(VECTOR4D &);
};
#endif // VEKTOR4D_H_INCLUDED
//project.cpp
#include <iostream>
#include "vector4d.h"
VECTOR4D &VECTOR4D::operator+=(VECTOR4D &K)
{
this->X += K.X;
this->Y += K.Y;
this->Z += K.Z;
this->T += K.T;
return *this;
}
During compilation i have got an error:
invalid use of template-name 'VECTOR4D' without an argument list
How I have to do this to make it correct?
VECTOR4D is a template class. All methods of template class must be implemented in header file (you can read here about it here: Why can templates only be implemented in the header file? )
You also should specify template parameter if you define template class method outside class declaration
template<typename TYPE>
VECTOR4D<TYPE> &VECTOR4D<TYPE>::operator+=(VECTOR4D<TYPE> &K)
{
this->X += K.X;
this->Y += K.Y;
this->Z += K.Z;
this->T += K.T;
return *this;
}
I the next simple constructor:
Vector(double x=0, double y=0) : x(x), y(y) {}
void operator+=(const Vector& other) {
this->x += other.x;
this->y += other.y;
}
But when I call it like this
Vector b();
Vector a(1,1);
and try to do a += b;
compiler gives me a lot of errors saying that no operators exist. However when I do like this:
Vector b(0,0);
or
Vector b(0);
everything works(((
Vector b(); doesn't create an object. It declares a function.
Vector b;
Vector a(1,1);
should work.
I have a header file that looks something like the following:
class Model {
private:
struct coord {
int x;
int y;
} xy;
public:
....
coord get() const {
return xy;
}
};
And in yet another file (assume ModelObject exists):
struct c {
int x;
int y;
void operator = (c &rhs) {
x = rhs.x;
y = rhs.y;
};
} xy;
xy = ModelObject->get();
The compiler throws an error that says there is no known covnersion from coord to c.
I believe it is because it doesn't know about coord type because it is declared inside of a class header. I can get around that by declaring the struct outside of the class, but I was wondering if it is possible to do the way I am, or is this generally considered bad practice
You would need an implicit conversion operator for Model::coord to c. For information on how to do this, I recommend taking a look at C++ Implicit Conversion Operators.
Also, when you mentioned "It does not know the type because it is in a class", you would use Model::coord as the struct type to the outside world (as long as coord is public, which in your current case it is not).
The code you have provided has two major problems:
1. You have not given a conversion from struct coord to struct c.
2. You can not use struct coord outside class Model because it is declared private.
Even if struct coord and struct c are similar, the compiler has very limited psychic powers. For the compiler the two structs are different even if they do essentially the same. One way to solve this is to give struct c an adequate assignement operator which takes a type of struct coord:
strutc c {
...
void operator = (const coord& rhs) { ... }
};
You have to make struct coord more public to be used outside class Model.
You can do this by:
a) declaring struct coord outside the class Model or
b) declaring it public inside class Model
If you do the latter you have to use the qualified name Model::coord to access the struct.
Remarks:
Consider changing the method
coord Model::get() const;
to
const coord& Model::get() const;
A subtle change that makes big difference. This saves an implicit construction of struct coord on the stack.
Consider changing the the operator
void c::operator = (c &rhs);
to
void c::operator = (const c& rhs);
because the assignment operator does not change the given argument struct c.
Const correctness is not just syntactic sugar but mandatory and it improves readability.
So this is my suggestion:
class Model {
public:
struct coord {
int x; int y;
};
private:
coord xy;
public:
const coord& get() const { return xy; }
};
struct c {
int x; int y;
void operator = (const c &rhs) { x = rhs.x; y = rhs.y; };
void operator = (const Model::coord &rhs) { x = rhs.x; y = rhs.y; };
};
Adding a constructor of c taking a coord is enough to make the compiler do the conversion. Now why do you have 2 different types for this ? Can't it be better to factorize this coord class out of Model and use them at both point ?