I am using Xcode and I have provided two headers below: Spheres.h and Vector3.h which both are suppose to be templates. Vector3.h compiles without any errors.
Spheres.h do not compile and returns this warning: "Expected ')'" and points to:
Sphere(const Vector3<T>& c,const float r);
^
This error occurs at any place inside Sphere.h where I have a Vector<T>. If I remove <T> the code can compile, I do not understand. Why? I want to be able to initialise Vector3<T> with same template<typename T> as Sphere<T>.
Please help!
Sphere.h
#ifndef SPHERE
#define SPHERE
#include "Vector3.h"
template <typename T>
class Sphere
{
public:
// Constructors
// Default
Sphere();
// Copy
Sphere(const Sphere<T>& sphere);
Sphere(const Vector3<T>& c, const float r);
// Destructor
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
void SetCenter(const Vector3<T>& vector);
void SetRadius(const float& r);
// Methods
// Calculate sphere area: A = 4 * PI * r^2
const float GetArea() const;
// Calculate sphere volume: V = (4 * PI * r^3) / 3
const float GetVolume() const;
// Return if given point of vector3 is within sphere
const bool PointIntersect(const Vector3<T>& point) const;
bool Overlap(const Sphere<T>& sphere);
// Tries to load data from a string
bool Load(std::string string) const;
// Operators
// Assignment operator
Sphere<T>& operator=(const Sphere<T>& sphere);
// Less than operator <
bool operator<(const Sphere<T>& s) const;
// Greater than operator >
bool operator>(const Sphere<T>& s) const;
// Less or equal operator <=
bool operator<=(const Sphere<T>& s) const;
// Greater or equal operator >=
bool operator>=(const Sphere<T>& s) const;
// Equal operator ==
bool operator ==(const Sphere<T>& s) const;
// Not equal operator !=
bool operator!=(const Sphere<T>& s) const;
// Print a sphere to console with cout
friend std::ostream& operator<<(std::ostream& out, const Sphere<T>& s);
private:
T radius;
Vector3<T> center;
};
// Implementation
// Constructor
// Default
template<typename T>
Sphere<T>::Sphere()
{
// Created empty sphere
}
// Copy
template<typename T>
Sphere<T>::Sphere(const Sphere<T>& sphere)
{
this->SetPosition(sphere.GetPosition());
this->SetRadius(sphere.GetRadius());
this->SetCenter(sphere.GetCenter());
}
template<typename T>
Sphere<T>::Sphere(const Vector3<T>& center,const float radius)
{
this->SetPosition(center);
this->radius = radius;
}
// Destructor
template<typename T>
Sphere<T>::~Sphere()
{
// Nothing to delete.
}
// Properties
// Get
template<typename T>
const Vector3<T>& Sphere<T>::GetCenter() const
{
return center;
}
template<typename T>
const float& Sphere<T>::GetRadius() const
{
return radius;
}
// Set
template<typename T>
void Sphere<T>::SetCenter(const Vector3<T>& vector)
{
this->SetPosition(vector);
}
template<typename T>
void Sphere<T>::SetRadius(const float& r)
{
radius = r;
}
// Methods
// Calculate sphere area: A = 4 * PI * r^2
template<typename T>
const float Sphere<T>::GetArea() const
{
float temp = 4 * pi * powf(this->GetRadius(), 2);
return temp;
}
// Calcutate sphere volume: V = (4 * PI * r^3) / 3
template<typename T>
const float Sphere<T>::GetVolume() const
{
float temp = (4 * pi * powf(radius, 3))/3;
return temp;
}
// Return if given point of vector3 is within sphere
template<typename T>
const bool Sphere<T>::PointIntersect(const Vector3<T>& point) const
{
if (point.GetDistance(this->GetCenter(), point) >= this->radius)
{
return true;
}
return false;
}
template<typename T>
bool Sphere<T>::Overlap(const Sphere<T>& sphere)
{
// Calculate the distance between the two spheres
float distance = Vector3::GetDistance(sphere.GetCenter(), this->GetCenter());
// Calculate the length of both radiances
float radiusSum = sphere.radius + this->radius;
// if the length of radiance is greater than the distace -> there is a overlap
if (radiusSum > distance)
return true;
return false;
}
// Tries to load data from a string
template<typename T>
bool Sphere<T>::Load(std::string string) const
{
return false;
}
// Operators
// Asignment operator
template<typename T>
Sphere& Sphere<T>::operator=(const Sphere<T>& sphere)
{
this->SetCenter(sphere.GetCenter());
this->radius = sphere.radius;
return *this;
}
// Less than operator <
template<typename T>
bool Sphere<T>::operator<(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
return false;
}
// Greater than operator >
template<typename T>
bool Sphere<T>::operator>(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
return false;
}
// Less or equal operator <=
template<typename T>
bool Sphere<T>::operator<=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Greater or equal operator >=
template<typename T>
bool Sphere<T>::operator >=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Equal operator ==
template<typename T>
bool Sphere<T>::operator ==(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 == v2)
return true;
return false;
}
// Not equal operator !=
template<typename T>
bool Sphere<T>::operator !=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 != v2)
return true;
return false;
}
// Print a sphere to console with cout
template<typename T>
std::ostream& operator<<(std::ostream& out, const Sphere<T>& s)
{
std::cout << "c:(" << s.GetCenter() << ") r:" << s.GetRadius();
return out;
}
#endif
Vector3.h
#ifndef VECTOR3
#define VECTOR3
// IO standard library
#include <iostream>
template<typename Type>
class Vector3
{
public:
// Constructor
Vector3(const Type& x, const Type& y, const Type& z);
// Copy constructor
Vector3(const Vector3<Type>& v);
// Destructor
~Vector3();
// Get properties
const Type& GetX() const;
const Type& GetY() const;
const Type& GetZ() const;
// Set properties
void SetX(const Type& value);
void SetY(const Type& value);
void SetZ(const Type& value);
// Methods
// Return length of the vector3<Type>
const float GetLength() const;
// Return the distance between two vector3<type>
const float GetDistance(const Vector3<Type>& v1, const Vector3<Type>& v2) const;
// Operators
// Assignment =
Vector3<Type>& operator=(const Vector3<Type>& v);
// Addition
Vector3<Type> operator+(const Vector3<Type>& v);
// Subtraction
Vector3<Type> operator-(const Vector3<Type>& v);
// Scalar product
float operator*(const Vector3<Type>& v);
// Multiplication
Vector3<Type> operator*(const float& s);
// Friend multiplication
friend Vector3<Type> operator*(const float& s, const Vector3<Type>& v);
// Cout: printing a vector3 to console
friend std::ostream& operator<<(std::ostream& out, const Vector3<Type>& v);
private:
Type x;
Type y;
Type z;
};
// Template implementation
// Constructor
template<typename Type>
Vector3<Type>::Vector3(const Type& x, const Type& y, const Type& z)
{
this->SetX(x);
this->SetY(y);
this->SetZ(z);
}
// Copy constructor
template<typename Type>
Vector3<Type>::Vector3(const Vector3<Type>& v)
{
this->SetX(x);
this->SetY(y);
this->SetZ(z);
}
// Destructor
template<typename Type>
Vector3<Type>::~Vector3<Type>()
{
// Nothin to delete
}
// Get Properties
template<typename Type>
const Type& Vector3<Type>::GetX() const
{
return this->x;
}
template<typename Type>
const Type& Vector3<Type>::GetY() const
{
return this->y;
}
template<typename Type>
const Type& Vector3<Type>::GetZ() const
{
return this->z;
}
// Set properties
template<typename Type>
void Vector3<Type>::SetX(const Type& value)
{
this->x = value;
}
template<typename Type>
void Vector3<Type>::SetY(const Type& value)
{
this->x = value;
}
template<typename Type>
void Vector3<Type>::SetZ(const Type& value)
{
this->x = value;
}
// Methods
// Return length of the vector3<Type>
template<typename Type>
const float Vector3<Type>::GetLength() const
{
float length = 0;
length = sqrtf(powf(x,2) + powf(y,2) + powf(z,2));
return length;
}
// Return the distance between two vector3's
template<typename Type>
const float Vector3<Type>::GetDistance(const Vector3<Type>& v1, const Vector3<Type>& v2) const
{
return sqrtf(powf((v2.x - v1.x), 2) +
powf((v2.y - v1.y), 2) +
powf((v2.z - v1.z), 2) );
}
// Operators
// Assignment
template<typename Type>
Vector3<Type>& Vector3<Type>::operator=(const Vector3<Type>& v)
{
this->SetX(v.x);
this->SetY(v.y);
this->SetZ(v.z);
return *this;
}
// Addition
template<typename Type>
Vector3<Type> Vector3<Type>::operator+(const Vector3<Type>& v)
{
Type x, y, z;
x = this->x + v.x;
y = this->y + v.y;
z = this->z + v.z;
Vector3<Type> temp(x, y, z);
return temp;
}
// Subtraction
template<typename Type>
Vector3<Type> Vector3<Type>::operator-(const Vector3<Type>& v)
{
Type x,y,z;
x = this->x - v.x;
y = this->y - v.y;
z = this->z - v.z;
Vector3<Type> temp(x, y, z);
return temp;
}
// Scalar product
template<typename Type>
float Vector3<Type>::operator*(const Vector3<Type>& v)
{
float scalarP = (this->GetX() * v.x) + (this->GetY() * v.y) + (this->GetZ() * v.z);
return scalarP;
}
template<typename Type>
Vector3<Type> Vector3<Type>::operator*(const float& s)
{
Vector3 temp(this->GetX() * s, this->GetY() * s, this->GetZ() * s);
return temp;
}
template<typename Type>
Vector3<Type> operator*(const float& s, const Vector3<Type>& v)
{
Vector3<Type> temp(v.x * s, v.y * s, v.z * s);
return temp;
}
// Cout: printing a vector3 to console
template<typename Type>
std::ostream& operator<<(std::ostream& out, const Vector3<Type>& v)
{
std::cout << "x:" << v.x
<< " y:" << v.y
<< " z:" << v.z;
return out;
}
#endif
The following compiles fine on gcc. Other than fixing the obvious syntax errors, I've also modified the constructors to fully initialize the object. Other possible solutions are to give Vector3 a default constructor (such that it can have a default initial value), or make center a Vector3<T>*.
#ifndef SPHERE
#define SPHERE
#include "vector3.h"
template <typename T>
class Sphere
{
public:
// Constructors
// Default
Sphere();
// Copy
Sphere(const Sphere<T>& sphere);
Sphere(const Vector3<T>& c, const float r);
// Destructor
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
void SetCenter(const Vector3<T>& vector);
void SetRadius(const float& r);
// Methods
// Calculate sphere area: A = 4 * PI * r^2
const float GetArea() const;
// Calculate sphere volume: V = (4 * PI * r^3) / 3
const float GetVolume() const;
// Return if given point of vector3 is within sphere
const bool PointIntersect(const Vector3<T>& point) const;
bool Overlap(const Sphere<T>& sphere);
// Tries to load data from a string
bool Load(std::string string) const;
// Operators
// Assignment operator
Sphere<T>& operator=(const Sphere<T>& sphere);
// Less than operator <
bool operator<(const Sphere<T>& s) const;
// Greater than operator >
bool operator>(const Sphere<T>& s) const;
// Less or equal operator <=
bool operator<=(const Sphere<T>& s) const;
// Greater or equal operator >=
bool operator>=(const Sphere<T>& s) const;
// Equal operator ==
bool operator ==(const Sphere<T>& s) const;
// Not equal operator !=
bool operator!=(const Sphere<T>& s) const;
// Print a sphere to console with cout
friend std::ostream& operator<<(std::ostream& out, const Sphere<T>& s);
private:
T radius;
Vector3<T> center;
};
// Implementation
// Constructor
// Default
template<typename T>
Sphere<T>::Sphere()
: radius(0), center(Vector3<T>(0,0,0))
{
// Created empty sphere
}
// Copy
template<typename T>
Sphere<T>::Sphere(const Sphere<T>& sphere)
: radius(sphere.radius), center(sphere.center)
{
}
template<typename T>
Sphere<T>::Sphere(const Vector3<T>& center, const float radius)
: radius(radius), center(center)
{
}
// Destructor
template<typename T>
Sphere<T>::~Sphere()
{
// Nothing to delete.
}
// Properties
// Get
template<typename T>
const Vector3<T>& Sphere<T>::GetCenter() const
{
return center;
}
template<typename T>
const float& Sphere<T>::GetRadius() const
{
return radius;
}
// Set
template<typename T>
void Sphere<T>::SetCenter(const Vector3<T>& vector)
{
this->SetPosition(vector);
}
template<typename T>
void Sphere<T>::SetRadius(const float& r)
{
radius = r;
}
// Methods
const float pi = 3.14;
// Calculate sphere area: A = 4 * PI * r^2
template<typename T>
const float Sphere<T>::GetArea() const
{
float temp = 4 * pi * powf(this->GetRadius(), 2);
return temp;
}
// Calcutate sphere volume: V = (4 * PI * r^3) / 3
template<typename T>
const float Sphere<T>::GetVolume() const
{
float temp = (4 * pi * powf(radius, 3))/3;
return temp;
}
// Return if given point of vector3 is within sphere
template<typename T>
const bool Sphere<T>::PointIntersect(const Vector3<T>& point) const
{
if (point.GetDistance(this->GetCenter(), point) >= this->radius)
{
return true;
}
return false;
}
template<typename T>
bool Sphere<T>::Overlap(const Sphere<T>& sphere)
{
// Calculate the distance between the two spheres
float distance = Vector3<T>::GetDistance(sphere.GetCenter(), this->GetCenter());
// Calculate the length of both radiances
float radiusSum = sphere.radius + this->radius;
// if the length of radiance is greater than the distace -> there is a overlap
if (radiusSum > distance)
return true;
return false;
}
// Tries to load data from a string
template<typename T>
bool Sphere<T>::Load(std::string string) const
{
return false;
}
// Operators
// Asignment operator
template<typename T>
Sphere<T>& Sphere<T>::operator=(const Sphere<T>& sphere)
{
this->SetCenter(sphere.GetCenter());
this->radius = sphere.radius;
return *this;
}
// Less than operator <
template<typename T>
bool Sphere<T>::operator<(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
return false;
}
// Greater than operator >
template<typename T>
bool Sphere<T>::operator>(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
return false;
}
// Less or equal operator <=
template<typename T>
bool Sphere<T>::operator<=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 < v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Greater or equal operator >=
template<typename T>
bool Sphere<T>::operator >=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 > v2)
return true;
if (v1 == v2)
return true;
return false;
}
// Equal operator ==
template<typename T>
bool Sphere<T>::operator ==(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 == v2)
return true;
return false;
}
// Not equal operator !=
template<typename T>
bool Sphere<T>::operator !=(const Sphere<T>& s) const
{
float v1 = this->GetVolume();
float v2 = s.GetVolume();
if (v1 != v2)
return true;
return false;
}
// Print a sphere to console with cout
template<typename T>
std::ostream& operator<<(std::ostream& out, const Sphere<T>& s)
{
std::cout << "c:(" << s.GetCenter() << ") r:" << s.GetRadius();
return out;
}
#endif
It is because your class Sphere requires Vector3 as template class. Like here:
~Sphere();
// Get properties
const Vector3<T>& GetCenter() const;
const float& GetRadius() const;
// Set Properties
But when you provide Sphere with Vector3<T> it will result in someting like this Vector3<T><T>
Related
Hey I am trying to implement Color space logic with c++.
As you may see every color space has its unique color components with its unique ranges and names, so I tried to implement a space component logic first.
template<typename T, T min, T max>
struct SpaceComponent {
static constexpr T MIN = min;
static constexpr T MAX = max;
T value;
SpaceComponent() = default;
SpaceComponent(T value) : value(static_cast<T>(value)) {
}
operator T() const {
return value > MAX ? MAX : value < MIN ? MIN : value;
}
operator SpaceComponent<T, MIN, MAX>() const {
return SpaceComponent<T, MIN, MAX>(static_cast<T>(value));
}
inline bool operator==(const SpaceComponent &other) const {
return value == other.value;
}
inline bool operator!=(const SpaceComponent &other) const {
return !(*this == other);
}
inline bool operator>(const SpaceComponent &other) const {
return value > other.value;
}
inline bool operator<(const SpaceComponent &other) const {
return !(*this > other) && *this != other;
}
inline bool operator>=(const SpaceComponent &other) const {
return !(*this < other);
}
inline bool operator<=(const SpaceComponent &other) const {
return !(*this > other);
}
inline SpaceComponent &operator=(const T &elem) {
if (value == elem) {
return *this;
}
value = static_cast<T>(elem);
return *this;
}
inline SpaceComponent &operator=(const SpaceComponent &other) {
if (*this == other) {
return *this;
}
*this = other.value;
return *this;
}
inline SpaceComponent &operator++() {
*this = static_cast<T>(++value);
return *this;
}
inline SpaceComponent &operator--() {
*this = static_cast<T>(--value);
return *this;
}
inline SpaceComponent operator+(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value + elem);
return result;
}
inline SpaceComponent operator-(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value - elem);
return result;
}
inline SpaceComponent operator*(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value * elem);
return result;
}
inline SpaceComponent operator/(const T &elem) const {
SpaceComponent result;
result = static_cast<T>(value / elem);
return result;
}
inline SpaceComponent operator+(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value + other.value);
return result;
}
inline SpaceComponent operator-(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value - other.value);
return result;
}
inline SpaceComponent operator*(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value * other.value);
return result;
}
inline SpaceComponent operator/(const SpaceComponent &other) const {
SpaceComponent result;
result = static_cast<T>(value / other.value);
return result;
}
inline SpaceComponent operator+=(const T &elem) {
*this = *this + elem;
return *this;
}
inline SpaceComponent operator-=(const T &elem) {
*this = *this - elem;
return *this;
}
inline SpaceComponent operator*=(const T &elem) {
*this = *this * elem;
return *this;
}
inline SpaceComponent operator/=(const T &elem) {
*this = *this / elem;
return *this;
}
inline SpaceComponent &operator+=(const SpaceComponent &other) {
*this = *this + other;
return *this;
}
inline SpaceComponent &operator-=(const SpaceComponent &other) {
*this = *this - other;
return *this;
}
inline SpaceComponent &operator*=(const SpaceComponent &other) {
*this = *this * other;
return *this;
}
inline SpaceComponent &operator/=(const SpaceComponent &other) {
*this = *this / other;
return *this;
}
};
By this logic I can create a color component of any type I want and it will not exit it's ranges(see implementation). Note that I am keeping MIN and MAX statically as I do not want my space component to increase in size(imagine what will be the size of 4096x4096 image in my ram if I do so).
Then I tried to implement different spaces of colors
struct RGB {
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline RGB operator+(const RGB &other) {
RGB rgb;
rgb.r = r + other.r;
rgb.g = g + other.g;
rgb.b = b + other.b;
return rgb;
}
};
struct ARGB {
SpaceComponent<unsigned char, 0, 255> a;
SpaceComponent<unsigned char, 0, 255> r;
SpaceComponent<unsigned char, 0, 255> g;
SpaceComponent<unsigned char, 0, 255> b;
inline ARGB operator+(const ARGB &other) {
ARGB argb;
argb.a = a + other.a;
argb.r = r + other.r;
argb.g = g + other.g;
argb.b = b + other.b;
return argb;
}
};
I stopped at this two as I realized that I need to write all operator overloading logic for all the spaces and that is huge work. I need somehow implement the operator overloading in one struct struct Space and derive all others from that. Note I cannot have any virtual methods as any pointer to vtable will increase the sizeof(Space) and it will raise problems that I already mentioned.I think I need something like template meta-programming to do this (using macros is my last choice) or using some technique like CRTP, as a draft I think my Space implementation can look like this.
using RGB = Space<SpaceComponent<unsigned char,0,255> r,SpaceComponent<unsigned char,0,255> g,SpaceComponent<unsigned char,0,255> b>;
I know that it's illegal to write like this, but can I have a struct which syntax will at least be nearly similar to this? Thx in advance.
I think it is possible if all components have the same type.
We can declare Space like this:
template <typename T, typename ...Components>
struct Space {...}
and use syntax like:
Space<unsigned char, Component<'r'>, Component<'g'>, Component<'b'>>;
where
template <char Id>
struct Component{...} // Component is just wrapper for ComponentImpl (for creation, to not duplicate types every time)
template <typename T> // your `SpaceComponent`
struct ComponentImpl{...}
Then inside Space we can use constexpr function to fill std::array<ComponentImpl>.
And inside operator+ just iterate through this array and sum all components.
Also we (probably) does not have to store T min, T max, we can use std::numeric_limits to get them.
UPDATE:
I wrote some prototype of this, take a look: https://godbolt.org/z/oEThae
How do i fix this?
I'm getting error: 'this' argument has type const but function is not marked const c++ overload operator
template <class T>
class Rational {
private:
T n = 0;
T d = 1;
public:
Rational() = default;
T numerator() {
return n;
}
T denominator() {
return d;
}
};
template <class T>
inline bool const operator ==(const Rational <T> & lhs, const Rational <T>& rhs) {
return lhs.numerator() * rhs.denominator() == lhs.denominator() * rhs.numerator();
}
My guess is that numerator() and denominator() member functions are not const member functions. Make them const. After that, the above function should work.
BTW, there is no need for the return type to be bool const. Keep it simple and change it to bool.
If numerator() and denominator() are to be used to directly assign to Rationals internal member variables as well as being used in const contexts, you need two sets of overloads. One mutable and one const:
// mutable interface
T& Rational::numerator();
T& Rational::denominator();
// const interface if T may only be a fundamental integral type
T Rational::numerator() const;
T Rational::denominator() const;
// const interface if sizeof(T) may be > sizeof(T*)
T const& Rational::numerator() const;
T const& Rational::denominator() const;
Note, only one of the const interfaces may be used so you need to select one of them.
Here's an example of how it can be done:
#include <iostream>
#include <type_traits>
template<typename T>
class Rational {
public:
// pass by value for fundamental types, by const& for other types
using by_value_or_by_const_ref =
std::conditional_t<std::is_fundamental_v<T>, T, T const&>;
Rational(by_value_or_by_const_ref n, by_value_or_by_const_ref d) :
m_numerator(n), m_denominator(d) {}
// mutable interface
T& numerator() { return m_numerator; }
T& denominator() { return m_denominator; }
// const interface
by_value_or_by_const_ref numerator() const { return m_numerator; }
by_value_or_by_const_ref denominator() const { return m_denominator; }
private:
T m_numerator;
T m_denominator;
};
template<class T>
inline bool operator==(const Rational<T>& lhs, const Rational<T>& rhs) {
// using const interface
return lhs.numerator() * rhs.denominator() ==
lhs.denominator() * rhs.numerator();
}
int main() {
Rational<int> a(10, 20);
Rational<int> b(10, 10);
// using mutable interface
a.denominator() /= 4;
b.numerator() *= 2;
std::cout << std::boolalpha << (a == b) << "\n";
}
I have a class in a header file which i am using mainly for the helper functions for vector manipulations (operator overloading of addition subtraction...etc) with the same class I have also another function and constructors used for when I define a new type this is the file below.
#pragma once
#include <math.h>
#include <assert.h>
class Vector2
{
public:
union
{
float Element[2];
struct { float X, Y; };
struct { float U, V; };
};
public:
Vector2() {}
Vector2(float p_fValue)
: X(p_fValue), Y(p_fValue) {}
Vector2(float p_x, float p_y)
: X(p_x), Y(p_y) {}
Vector2(const Vector2 &p_vector)
: X(p_vector.X), Y(p_vector.Y) {}
float operator[](int p_nIndex) const { return Element[p_nIndex]; }
float& operator[](int p_nIndex) { return Element[p_nIndex]; }
inline void Set(float p_x, float p_y) {
X = p_x; Y = p_y;
}
inline bool Equals(const Vector2 &p_vector, const float p_epsilon = 1e-5f) const
{
if (fabs(X - p_vector.X) > p_epsilon) return false;
if (fabs(Y - p_vector.Y) > p_epsilon) return false;
return true;
}
Vector2& operator=(const Vector2 &p_vector)
{
X = p_vector.X;
Y = p_vector.Y;
return *this;
}
inline bool operator==(const Vector2 &p_vector) const {
return Equals(p_vector);
}
inline bool operator!=(const Vector2& p_vector) const {
return !(*this == p_vector);
}
inline Vector2 operator*(float p_fValue) const {
return Vector2(p_fValue * X, p_fValue * Y);
}
inline Vector2 operator/(float p_fValue) const
{
assert(p_fValue != 0.f);
return Vector2(*this * (1.0f / p_fValue));
}
inline Vector2 operator*(const Vector2 &p_vector) const {
return Vector2(p_vector.X * X, p_vector.Y * Y);
}
inline Vector2 operator+(const Vector2 &p_vector) const {
return Vector2(X + p_vector.X, Y + p_vector.Y);
}
inline Vector2 operator-(const Vector2 &p_vector) const {
return Vector2(X - p_vector.X, Y - p_vector.Y);
}
inline Vector2 operator-(void) const {
return Vector2(-X, -Y);
}
inline Vector2& operator*=(float p_fValue) {
return *this = *this * p_fValue;
}
inline Vector2& operator*=(const Vector2 &p_vector) {
return *this = *this * p_vector;
}
inline Vector2& operator/=(float p_fValue) {
return *this = *this / p_fValue;
}
inline Vector2& operator+=(const Vector2 &p_vector) {
return *this = *this + p_vector;
}
inline Vector2& operator-=(const Vector2 &p_vector) {
return *this = *this - p_vector;
}
inline float MaxComponent() const {
return std::max(X, Y);
}
inline float MinComponent() const {
return std::min(X, Y);
}
inline float MaxAbsComponent() const {
return std::max(fabs(X), fabs(Y));
}
inline float MinAbsComponent() const
{
return std::min(fabs(X), fabs(Y));
}
static Vector2 Max(const Vector2 &p_vector1, const Vector2 &p_vector2)
{
return Vector2(std::max(p_vector1.X, p_vector2.X),
std::max(p_vector1.Y, p_vector2.Y));
}
static Vector2 Min(const Vector2 &p_vector1, const Vector2 &p_vector2)
{
return Vector2(std::min(p_vector1.X, p_vector2.X),
std::min(p_vector1.Y, p_vector2.Y));
}
inline float Length(void) const {
return sqrt(X * X + Y * Y);
}
inline float LengthSquared(void) const {
return X * X + Y * Y;
}
inline void Normalize(void) {
*this = Vector2::Normalize(*this);
}
inline float Dot(const Vector2 &p_vector) const {
return Vector2::Dot(*this, p_vector);
}
inline float AbsDot(const Vector2 &p_vector) const {
return Vector2::AbsDot(*this, p_vector);
}
static float Dot(const Vector2 &p_vector1, const Vector2 &p_vector2) {
return p_vector1.X * p_vector2.X + p_vector1.Y * p_vector2.Y;
}
static float AbsDot(const Vector2 &p_vector1, const Vector2 &p_vector2) {
return fabs(p_vector1.X * p_vector2.X +
p_vector1.Y * p_vector2.Y);
}
static Vector2 Normalize(const Vector2 &p_vector) {
return p_vector / sqrt(p_vector.Length());
}
static float DistanceSquared(const Vector2 &p_point1, const Vector2 &p_point2) {
return (p_point2 - p_point1).LengthSquared();
}
static float Distance(const Vector2 &p_point1, const Vector2 &p_point2) {
return (p_point2 - p_point1).Length();
}
};
inline Vector2 operator*(float p_fValue, const Vector2 &p_vector) {
return Vector2(p_fValue * p_vector.X, p_fValue * p_vector.Y);
}
This is quite a trivial and there is probably not much more to add to this code it is just that I want the above code to be divided into a struct with the constructors and a class with the helper functions. Thats all.
Only way I can see is to use inheritance.
Make Vector2 a base class that you won't use, then make another class that inherits everything from it where helper functions are implemented.
struct Vector2Base
{
union
{
float Element[2];
struct { float X, Y; };
struct { float U, V; };
}
};
struct Vector2 : public Vector2Base
{
Vector2& operator=(const Vector2 &p_vector)
{
X = p_vector.X;
Y = p_vector.Y;
return *this;
}
};
Then you only use the derived class and never the base class.
I am not very familiar with templates in C++ so I am struggling to solve the following problem.
I have the classes Vector2D and Vector3D but I want them to inherit from a class Vector. To be able to define common functions in Vector I am using CRTP (Curiously Recurring Template Pattern).
This is a shortend version of my Vector class:
#pragma once
#include "../stdafx.h"
template <class VectorImpl>
class Vector {
public:
VectorImpl& operator=(const VectorImpl& other);
virtual const float operator*(const VectorImpl& other) const = 0;
friend const VectorImpl operator*(const float& scalar, const VectorImpl& other);
virtual VectorImpl& operator*=(const float& scalar) = 0;
float abs() const;
virtual std::string toString() const = 0;
virtual ~Vector() = 0 {};
protected:
virtual void copyFrom(const VectorImpl& other) = 0;
};
-----------------------------------------------------------------------------------------
#include "Vector.h"
#include "Vector2D.h" // edit
#include "Vector3D.h" // edit
template <class VectorImpl>
VectorImpl& Vector<VectorImpl>::operator=(const VectorImpl& other) {
this->copyFrom(other);
// edit
// return *this;
return static_cast<VectorImpl&>(*this);
}
template <class VectorImpl>
const VectorImpl operator*(const float& scalar, const VectorImpl& other) {
VectorImpl result = other;
result *= scalar;
return result;
}
template <class VectorImpl>
float Vector<VectorImpl>::abs() const {
const VectorImpl thisImpl = static_cast<const VectorImpl&>(*this); // edit
return std::sqrt(thisImpl * thisImpl);
}
// edit
template class Vector<Vector2D>;
template class Vector<Vector3D>;
And this is a shortend version of my Vector2D class:
#pragma once
#include "../stdafx.h"
#include "Vector.h"
class Vector2D :
public Vector<Vector2D> {
public:
Vector2D();
Vector2D(const Vector2D& other);
Vector2D(const float& xPos, const float& yPos);
const float operator*(const Vector2D& other) const;
Vector2D& operator*=(const float& scalar);
std::string toString() const;
~Vector2D();
protected:
void copyFrom(const Vector2D& other);
private:
float xPos;
float yPos;
};
-----------------------------------------------------------------------------------------
#include "Vector2D.h"
Vector2D::Vector2D() :
xPos(0.0f),
yPos(0.0f) {
}
Vector2D::Vector2D(const Vector2D& other) {
this->copyFrom(other);
}
void Vector2D::copyFrom(const Vector2D& other) {
if (this != &other) {
this->xPos = other.getXPos();
this->yPos = other.getYPos();
}
}
Vector2D::Vector2D(const float& xPos, const float& yPos) {
this->xPos = xPos;
this->yPos = yPos;
}
const float Vector2D::operator*(const Vector2D& other) const {
return this->xPos * other.getXPos() + this->yPos * other.getYPos();
}
Vector2D& Vector2D::operator*=(const float& scalar) {
this->xPos *= scalar;
this->yPos *= scalar;
return *this;
}
std::string Vector2D::toString() const {
std::string ret = std::to_string(this->xPos);
ret += " ";
ret += std::to_string(this->yPos);
return ret;
}
Vector2D::~Vector2D() {
// intentionally left blank
}
The problem is, for every call of a method from Vector2D (Vector3D respectively) that is implemented in Vector I get an LNK2019 error (unresolved external symbol 'symbol' referenced in function 'function').
I am quite sure that I am doing somethin wrong with my template implementation but I can't figure out what it is. I am researching for hours now.
I appreciate any help, so thanks in advance.
EDIT:
I added the necessary instantiations of my template classes but now I get casting errors. Adding
VectorImpl result = static_cast<const VectorImpl>(*this);
or
VectorImpl result = static_cast<VectorImpl>(*this);
doesn't change the problem. What I am I still missing here?
EDIT 2:
Okay of course it hast to be static_cast<const VectorImpl&>(*this).
I also added these casts but now I get that damn linking error again. This time only the functions friend operator* and abs can't be linked. I don't see much difference to the other functions. So why are they problematic?
I have a class:
class Point3D : public Point{
protected:
float x;
float y;
float z;
public:
Point3D(){x=0; y=0; z=0;}
Point3D(const Point3D & point){x = point.x; y = point.y; z = point.z;}
Point3D(float _x,float _y,float _z){x = _x; y = _y; z = _z;}
inline const Point3D operator+(const Vector3D &);
const Point3D & operator+(const Point3D &point){
float xT = x + point.getX();
float yT = y + point.getY();
float zT = z + point.getZ();
return Point3D(xT, yT, zT);
}
...
When I use it that way:
Point3D point = Point3D(10,0,10);
Everything works fine.
When I write:
Point3D point = Point3D(10,0,10);
Point3D point2 = Point3D(0,0,0) + point();
Also it's ok (point2 = point). When I add something more than (0,0,0) it's also working.
But when I want just to:
Point3D point = Point3D(10,0,10);
someFunction( Point3D(0,0,0) + point ); //will get strange (x,y,z)
The function get value of some (in my opinion) random (x,y,z). Why?
What's even stranger, in that similar example everything will be working again:
Point3D point = Point3D(10,0,10);
Point3D point2 = Point3D(0,0,0) + point;
someFunction( point2 ); // will get (10,0,10)
What's the reason for that strange behaviour?
The operator+() is returning a dangling reference, the returned reference is referring to a Point3D instance that is destroyed when operator+() returns. Change to:
Point3D operator+(const Point3D &point) const {
so a copy is returned, and make it const as it has no reason to be changing anything.
The typical pattern for classes that support arithmetic operators is
class Foo
{
public:
Foo & operator+=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator-=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator*=(Foo const & rhs) { /* ... */ return *this; }
Foo & operator/=(Foo const & rhs) { /* ... */ return *this; }
};
Foo operator+(Foo const & lhs, Foo const & rhs) { return Foo(lhs) += rhs; }
Foo operator-(Foo const & lhs, Foo const & rhs) { return Foo(lhs) -= rhs; }
Foo operator*(Foo const & lhs, Foo const & rhs) { return Foo(lhs) *= rhs; }
Foo operator/(Foo const & lhs, Foo const & rhs) { return Foo(lhs) /= rhs; }
You are returning a reference to a local variable from operator+ which will get invalidated once the function returns, you need to return a copy of the Point3D created.