Binary operator overloading with class and constant in C++ - c++

I am trying to do operator overloading
My header is:
class Nyble
{
public:
Nyble();
Nyble(const Nyble& n);
Nyble& operator=(const Nyble& n);
~Nyble();
Nyble operator+(const char a);
Nyble operator-(const char a);
Nyble operator+(Nyble& n1);
Nyble operator+();
unsigned char getData();
private:
// Do not change this data
unsigned char data;
}
Source:
#include "Nyble.h"
unsigned char Nyble::getData()
{
return this->data;
}
Nyble Nyble::operator+(const char val)
{
return Nyble(getData()+val);
}
Nyble Nyble::operator-(const char value)
{
return Nyble(value + getData()) ;
}``
I am getting an error saying no suitable constructor exists to convert int to Nyble. If so, what constructor should I declare? Else what changes should I make to the overloading function?

You need to add a constructor for Nyble(getData() + val); and Nyble(value + getData()) to work:
class Nyble {
public:
explicit Nyble(char d); // add this
// ...
};
Nyble::Nyble(char d) : data(d) {} // and the implementation
Though, I recommend that you instead implement operator+ and operator- as free functions and make operator+= and operator-= member functions.
It could look like this:
class Nyble {
public:
Nyble() = default;
explicit Nyble(unsigned char d);
// implement operator+= and operator-= as member functions
Nyble& operator+=(const Nyble& n1);
Nyble& operator-=(const Nyble& n1);
unsigned char getData() const;
unsigned char& getData();
private:
unsigned char data = 0;
};
// operator+ and operator- as free functions:
Nyble operator+(Nyble lhs, const Nyble& rhs);
Nyble operator-(Nyble lhs, const Nyble& rhs);
Nyble::Nyble(unsigned char d) : data(d) {}
// the implementation of the member operator overloads:
Nyble& Nyble::operator+=(const Nyble& rhs) {
data += rhs.data;
return *this;
}
Nyble& Nyble::operator-=(const Nyble& rhs) {
data -= rhs.data;
return *this;
}
unsigned char Nyble::getData() const { return data; }
unsigned char& Nyble::getData() { return data; }
// now the free functions can use the member functions
// `operator+=` and `operator-=`:
Nyble operator+(Nyble lhs, const Nyble& rhs) {
return lhs += rhs;
}
Nyble operator-(Nyble lhs, const Nyble& rhs) {
return lhs += rhs;
}

Related

C++ struct field name and types from variadic template

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

'this' argument has type const but function is not marked const c++ overload operator

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";
}

std::find with two different types

I am trying to use std::find with two different types but providing the necessary boolean operators.
class FooDetails
{
public:
FooDetails(int size = 5)
: m_size(size) { /* empty */ }
bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
int m_size;
};
class Foo
{
public:
Foo(int size)
: m_details(size) { /* empty */}
bool operator==(const Foo& other) const { return m_details == other.m_details; }
bool operator==(const FooDetails& other) const {return m_details == other; }
bool operator<(const Foo& other) const { return m_details < other.m_details; }
bool operator<(const FooDetails& other) const { return m_details < other; }
FooDetails m_details;
};
bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }
int main() {
std::vector<Foo> haystack = { FooDetails(5), FooDetails(6), FooDetails(7) };
FooDetails needle(6);
std::find(haystack.begin(), haystack.end(), needle);
return 0;
}
Since std::find uses operator== I would expect this to work, since all necessary functions are provided. However this does not compile. Why is that and how do I fix it?
I know I could use std::find_if, but I assume that's a bit slower and even if it's not I'd like to know why std::find doesn't work.
I've changed your code to this:
#include <algorithm>
class FooDetails
{
public:
FooDetails(int size = 5)
: m_size(size) { /* empty */ }
bool operator<(const FooDetails& other) const { return m_size < other.m_size; }
bool operator==(const FooDetails& other) const { return m_size == other.m_size; }
private:
int m_size;
};
class Foo
{
public:
Foo(int size)
: m_details(size) { /* empty */}
FooDetails m_details;
};
bool operator==(const FooDetails& lhs, const Foo& rhs) { return lhs == rhs.m_details; }
bool operator==(const Foo& lhs, const FooDetails& rhs) {return lhs.m_details == rhs; }
bool operator<(const FooDetails& lhs, const Foo& rhs) { return lhs < rhs.m_details; }
bool operator<(const Foo& lhs, const FooDetails& rhs) { return lhs.m_details < rhs; }
int main() {
std::vector<Foo> haystack = { Foo(5), Foo(6), Foo(7) };
FooDetails needle(6);
std::find(haystack.begin(), haystack.end(), needle);
return 0;
}
And it successfully compiles. Your original version contains two errors:
You try to create std::vector<Foo> initialising it with std::initialization_list<FooDetails>.
You have provided too many comparison operators: both free versions and members of the Foo struct. So during lookup compiler complains that it doesn't know which one of them to choose. You should leave only one of them.
You have no such constructor in Foo class which constructs it from FooDetails. You need to define the following and your code will work:
Foo(const FooDetails& d) : m_details(d) {}

class method signature with *const* or without *const*?

I get the following error in Eclipse when trying to compile (c++)
../CardDeck.cpp:17:22: error: passing ‘const CardDeck’ as ‘this’ argument of ‘int CardDeck::size()’ discards qualifiers [-fpermissive]
if I change int size() method to int size() const the error msg is gone and its compiled. I dont know why ?
the .H file is the following :
#include "Card.h"
#include <vector>
using namespace std;
class CardDeck{
private:
vector<Card*> deck;
public:
int size();
CardDeck();
CardDeck(const CardDeck& rhs);
CardDeck& operator=(const CardDeck& rhs);
Card& draw();
Card& top();
bool isEmpty();
void clear();
int value();
CardDeck& operator+=(const CardDeck& rhs); /// not sure if to return ref
CardDeck& operator+(const CardDeck& rhs);
friend CardDeck& operator*(unsigned int num,CardDeck& rhs);
friend CardDeck& operator*(CardDeck& lhs,unsigned int num);
bool operator<=(const CardDeck& rhs );
bool operator>=(const CardDeck& rhs);
bool operator<(const CardDeck& rhs);
bool operator>(const CardDeck& rhs);
bool operator==(const CardDeck& rhs);
bool operator!=(const CardDeck& rhs);
Card* operator[](int i);
};
and the C++ file is :
#include "CardDeck.h"
int CardDeck::size() {
return this->deck.size();
}
CardDeck::CardDeck(){};
CardDeck::CardDeck(const CardDeck& rhs){
this->clear();
int i;
for (i=0;i<rhs.size();i++){
Card* current_card = rhs.deck[i];
Card* new_copy = new Card(*current_card);
this->deck.push_back(new_copy);
}
}
Card* CardDeck::operator[](int i) {
return this->deck[i];
}
void CardDeck::clear(){
vector<Card*>::iterator it ;
for(it=this->deck.begin();it != this->deck.end();++it){
Card* temp = *it;
this->deck.erase(it);
delete(temp);
}
}
In your copy constructor CardDeck::CardDeck(const CardDeck& rhs), rhs is a reference to a const CardDeck object.
So rhs.size() will not compile unless size() is explicitly marked as being const. That's what your compiler is telling you.
It's good practice to have your code as const-correct as possible as this prevents errant changes to the member data in a class. Really, isEmpty(), and possibly value() should be marked const too, as should all the overloaded relational operators.

c++ error: qualifiers can only be specified

I am not completely sure why this is generating that error:
const class MyString {
public:
MyString() { _len = 0; _str = NULL; }
MyString(const char* in);
MyString(const MyString&);
~MyString();
int set(const char*);
int set(const MyString&);
int setLength(int len) { _len = len; return 0; }
int getLength() { return _len; }
char * getStr() { return _str; }
int getStr(char* out) const;
MyString operator+(const MyString & in);
MyString operator+(const char* in);
MyString operator+(const char in) {const char* temp = &in; return *this + temp; }
MyString operator=(const MyString & in)
{ this->set(in); return *this; }
MyString operator=(const char* in)
{ if(in) this->set(in); return *this; }
MyString operator=(const char in) {const char* temp = &in; return *this = temp; }
MyString operator+=(const MyString & in)
{ this->set(*this + in); return *this; }
MyString operator+=(const char* in)
{ if(in) this->set(*this + in); return *this; }
MyString operator+=(const char in) { return (*this + in); }
int operator==(const MyString& in);
int operator!=(const MyString& in);
int operator==(const char* in);
int operator!=(const char* in);
friend ostream& operator<<(ostream& os, const MyString & in)
{ os << in._str; return os; }
protected:
char * _str;
int _len;
};
The error is being generated at the last line. The only code before that definition are 'standard' #includes and using namespace std.
The error message you posted is not complete, but nevermind that.
Long story short: remove the const qualifier at the very top of your class declaration, the one just before the class keyword. You can only add cv-qualifiers (const / volatile) either on variables or methods.