Consider this following class Operand
: It is a pretty straight forward class as it takes in a single Parameter and defines a bunch of overloaded operators and for simplicity of testing this class I chose to use a float
type since there are division operators. If you notice with some of the operators they are defined as friends so that one is able to do this in their code:
Edit Someone asked in the comments what does
inline friend Operand Operand::operator+( const Operand& A, const Operand B )
mean? It is an overloaded operator but since one is already defined for the class itself as a member this is declared as a friend to the class and is defined within the class but is not a class member. This allows the user to add two Operand class instances or objects together and returns back the newly calculated value as an Operand object. I'll add comments to the snippet
section as to what overloaded operators are being used.
snippet
Operand A( 2.3f );
Operand B( 4.5f );
Operand C( 0 );
Operand D( 0 );
C = A + B; // inline friend Operand Operand::operator+( const Operand& A, const Operand B );
D = C + 2.5f; // Overloaded Operator Defined as Class Member
D = 3.4f + B; // inline friend Operand Operand::operator+( const Value& value, const Operand A );
I've done this with the 4 common arithmetic operations +-*/
where one operator is defined in the class as a member and 2 friend operators are defined for each of the 4 operations. Here is the class definition.
Operand.h
#ifndef OPERAND_H
#define OPERAND_H
class Operand {
public:
static const float ZERO;
protected:
float operand_;
public:
explicit Operand( float a = float() ) : operand_( a ) {}
inline float getOperand() const {
return operand_;
}
inline Operand& operator+=( const float& value ) {
operand_ += value;
return *this;
}
inline Operand& operator-=( const float& value ) {
operand_ -= value;
return *this;
}
inline Operand& operator*=( const float& value ) {
operand_ *= value;
return *this;
}
inline Operand& operator/=( const float& value ) {
if ( isZero( value ) ) {
operand_ = 0;
} else {
operand_ /= value;
}
}
inline Operand operator+() const { // Unary
return *this;
}
inline Operand operator+( const float& value ) const {
return Operand( operand_ + value );
}
inline Operand operator-() const { // Unary
return Operand( -operand_ );
}
inline Operand operator-( const float& value ) const {
return Operand( operand_ - value );
}
inline Operand operator*( const float& value ) const {
return Operand( operand_ * value );
}
inline Operand operator/( const float& value ) const {
if ( isZero( value ) ) {
return Operand( 0 );
} else {
return Operand( operand_ / value );
}
}
inline friend Operand Operand::operator+( const Operand& A, const Operand B ) {
return Operand( A.getOperand() + B.getOperand() );
}
inline friend Operand Operand::operator+( const float& value, Operand A ) {
return Operand( value + A.getOperand() );
}
inline friend Operand Operand::operator-( const Operand& A, const Operand B ) {
return Operand( A.getOperand() - B.getOperand() );
}
inline friend Operand Operand::operator-( const float& value, Operand A ) {
return Operand( value - A.getOperand() );
}
inline friend Operand Operand::operator*( const Operand& A, const Operand B ) {
return Operand( A.getOperand() * B.getOperand() );
}
inline friend Operand Operand::operator*( const float& value, const Operand A ) {
return Operand( value * A.getOperand() );
}
inline friend Operand Operand::operator/( const Operand& A, const Operand B ) {
if ( isZero( B.getOperand() ) ) {
return Operand( 0 );
} else {
return Operand( A.getOperand() / B.getOperand() );
}
}
inline friend Operand Operand::operator/( const float& value, const Operand A ) {
if ( isZero( A.getOperand() ) ) {
return Operand( 0 );
} else {
return Operand( value / A.getOperand() );
}
}
inline static bool isZero( float value ) {
if ( (value > -ZERO) && (value < ZERO) ) {
return true;
}
return false;
} // isZero
}; // Operand
// #include "Operand.inl"
#endif // OPERAND_H
Operand.cpp
#include "Operand.h"
const float Operand::ZERO = static_cast<float>(1e-7);
What I want to do is to template this class.
So here is the same class only defined as a class template:
OperandT.h
#ifndef OPERAND_T_H
#define OPERAND_T_H
template <typename T>
class OperandT {
public:
static const T ZERO;
protected:
T operand_;
public:
explicit OperandT<T>( T a = T() ) : operand_( a ) {}
inline T getOperand() const {
return operand_;
} // getOperand
inline OperandT<T>& operator+=( const T& value ) {
operand_ += value;
return *this;
} // operator+=
inline OperandT<T>& operator-=( const T& value ) {
operand_ -= value;
return *this;
} // operator-=
inline OperandT<T>& operator*=( const T& value ) {
operand_ *= value;
return *this;
} // operator*=
inline OperandT<T>& operator/=( const T& value ) {
if ( isZero( value ) ) {
operand_ = 0;
} else {
operand_ /= value;
}
} // operator/=
inline OperandT<T> operator+() const {
return *this;
} // operator+ Unary
inline OperandT<T> operator+( const T& value ) const {
return OperandT<T>( operand_ + value );
} // operator+ Binary
inline OperandT<T> operator-() const {
return OperandT<T>( -operand_ );
} // operator- Unary (Negate Value)
inline OperandT<T> operator-( const T& value ) const {
return OperandT<T>( operand_ - value );
} // opeator- Binary (Subtraction)
inline OperandT<T> operator*( const T& value ) const {
return OperandT<T>( operand_ * value );
} // operator* Post Multiply
inline OperandT<T> operator/( const T& value ) const {
if ( isZero( value ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( operand_ / value );
}
} // operator/ Post Divide
/*/ Having Trouble With Operators When Using Templates and Friends
inline friend OperandT<T> OperandT<T>::operator+( const OperandT<T>& A, const OperandT<T> B ) {
return OperandT<T>( A.getOperand() + B.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator+( const float& value, OperandT<T> A ) {
return OperandT<T>( value + A.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator-( const OperandT<T>& A, const OperandT<T> B ) {
return OperandT<T>( A.getOperand() - B.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator-( const float& value, OperandT<T> A ) {
return OperandT<T>( value - A.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator*( const OperandT<T>& A, const OperandT<T> B ) {
return OperandT<T>( A.getOperand() * B.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator*( const float& value, const OperandT<T> A ) {
return OperandT<T>( value * A.getOperand() );
}
inline friend OperandT<T> OperandT<T>::operator/( const OperandT<T>& A, const OperandT<T> B ) {
if ( isZero( B.getOperand() ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( A.getOperand() / B.getOperand() );
}
}
inline friend OperandT<T> OperandT<T>::operator/( const float& value, const OperandT<T> A ) {
if ( isZero( A.getOperand() ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( value / A.getOperand() );
}
} */
inline static bool isZero( T value ) {
if ( (value > -ZERO) && (value < ZERO) ) {
return true;
}
return false;
} // isZero
}; // OperandT
#include "OperandT.inl"
#endif // OPERAND_T_H
OperandT.cpp
#include "OperandT.h"
template <typename T>
const T OperandT<T>::ZERO = static_cast<T>( static_cast<float>(1e-7) );
With the friend operators commented out it compiles and the in class defined operators work but when I uncomment the lower section of the class I end up getting compiler errors.
The few questions that I have are:
After having a brief conversation with Danh
in the comment section He has brought to my attention that the way I was able to implement the overloaded friend operators
in visual studio 2013 - 15
should be considered a bug. Yes it will compile and run without error on visual studio as well as this website for visual studio compilers rextesters.com. He has stated that the proper way to implement overloaded friend operators is as such:
The proper way is
friend Operand operator+(Operand A, Operand B)
orfriend Operand operator+(const Operand& A, const Operand& B)
, I'm going to file a bug to MSFT – Danh
He also showed me where it failed to compile under GCC or Clang from here: http://melpon.org
I told him I would take this into consideration and I did. So I updated my Operand
header file accordingly and it compiles, builds and runs correctly.
Then I went ahead and fixed the template version and it is working as well.
Here are the updated class headers.
Operand.h
#ifndef OPERAND_H
#define OPERAND_H
class Operand {
public:
static const float ZERO;
protected:
float operand_;
public:
explicit Operand( float a = float() ) : operand_( a ) {}
inline float getOperand() const {
return operand_;
}
inline Operand& operator+=( const float& value ) {
operand_ += value;
return *this;
}
inline Operand& operator-=( const float& value ) {
operand_ -= value;
return *this;
}
inline Operand& operator*=( const float& value ) {
operand_ *= value;
return *this;
}
inline Operand& operator/=( const float& value ) {
if ( isZero( value ) ) {
operand_ = 0;
} else {
operand_ /= value;
}
}
inline Operand operator+() const { // Unary
return *this;
}
inline Operand operator+( const float& value ) const {
return Operand( operand_ + value );
}
inline Operand operator-() const { // Unary
return Operand( -operand_ );
}
inline Operand operator-( const float& value ) const {
return Operand( operand_ - value );
}
inline Operand operator*( const float& value ) const {
return Operand( operand_ * value );
}
inline Operand operator/( const float& value ) const {
if ( isZero( value ) ) {
return Operand( 0 );
} else {
return Operand( operand_ / value );
}
}
inline friend Operand operator+( const Operand& A, const Operand& B ) {
return Operand( A.getOperand() + B.getOperand() );
}
inline friend Operand operator+( const float& value, const Operand& A ) {
return Operand( value + A.getOperand() );
}
inline friend Operand operator-( const Operand& A, const Operand& B ) {
return Operand( A.getOperand() - B.getOperand() );
}
inline friend Operand operator-( const float& value, const Operand& A ) {
return Operand( value - A.getOperand() );
}
inline friend Operand operator*( const Operand& A, const Operand& B ) {
return Operand( A.getOperand() * B.getOperand() );
}
inline friend Operand operator*( const float& value, const Operand& A ) {
return Operand( value * A.getOperand() );
}
inline friend Operand operator/( const Operand& A, const Operand& B ) {
if ( isZero( B.getOperand() ) ) {
return Operand( 0 );
} else {
return Operand( A.getOperand() / B.getOperand() );
}
}
inline friend Operand operator/( const float& value, const Operand& A ) {
if ( isZero( A.getOperand() ) ) {
return Operand( 0 );
} else {
return Operand( value / A.getOperand() );
}
}
inline static bool isZero( float value ) {
if ( (value > -ZERO) && (value < ZERO) ) {
return true;
}
return false;
}
}; // Operand
//#include "Operand.inl"
#endif // OPERAND_H
OperandT.h
#ifndef OPERAND_T_H
#define OPERAND_T_H
template <typename T>
class OperandT {
public:
static const T ZERO;
protected:
T operand_;
public:
explicit OperandT<T>( T a = T() ) : operand_( a ) {}
inline T getOperand() const {
return operand_;
}
inline OperandT<T>& operator+=( const T& value ) {
operand_ += value;
return *this;
}
inline OperandT<T>& operator-=( const T& value ) {
operand_ -= value;
return *this;
}
inline OperandT<T>& operator*=( const T& value ) {
operand_ *= value;
return *this;
}
inline OperandT<T>& operator/=( const T& value ) {
if ( isZero( value ) ) {
operand_ = 0;
} else {
operand_ /= value;
}
}
inline OperandT<T> operator+() const {
return *this;
}
inline OperandT<T> operator+( const T& value ) const {
return OperandT<T>( operand_ + value );
}
inline OperandT<T> operator-() const {
return OperandT<T>( -operand_ );
}
inline OperandT<T> operator-( const T& value ) const {
return OperandT<T>( operand_ - value );
}
inline OperandT<T> operator*( const T& value ) const {
return OperandT<T>( operand_ * value );
}
inline OperandT<T> operator/( const T& value ) const {
if ( isZero( value ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( operand_ / value );
}
}
inline friend OperandT<T> operator+( const OperandT<T>& A, const OperandT<T>& B ) {
return OperandT<T>( A.getOperand() + B.getOperand() );
}
inline friend OperandT<T> operator+( const float& value, const OperandT<T>& A ) {
return OperandT<T>( value + A.getOperand() );
}
inline friend OperandT<T> operator-( const OperandT<T>& A, const OperandT<T>& B ) {
return OperandT<T>( A.getOperand() - B.getOperand() );
}
inline friend OperandT<T> operator-( const float& value, const OperandT<T>& A ) {
return OperandT<T>( value - A.getOperand() );
}
inline friend OperandT<T> operator*( const OperandT<T>& A, const OperandT<T>& B ) {
return OperandT<T>( A.getOperand() * B.getOperand() );
}
inline friend OperandT<T> operator*( const float& value, const OperandT<T>& A ) {
return OperandT<T>( value * A.getOperand() );
}
inline friend OperandT<T> operator/( const OperandT<T>& A, const OperandT<T>& B ) {
if ( isZero( B.getOperand() ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( A.getOperand() / B.getOperand() );
}
}
inline friend OperandT<T> operator/( const float& value, const OperandT<T>& A ) {
if ( isZero( A.getOperand() ) ) {
return OperandT<T>( 0 );
} else {
return OperandT<T>( value / A.getOperand() );
}
}
inline static bool isZero( T value ) {
if ( (value > -ZERO) && (value < ZERO) ) {
return true;
}
return false;
}
}; // OperandT
//#include "OperandT.inl"
#endif // OPERAND_T_H
Now my code is working properly using templates all thanks to Danh
!