interesting issue operator overloading [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator overloading
What causes C++ compiler error: must have argument of class or enumerated type?
I am trying to play a little bit with operator overloading and genericity in C++ and I seem to have 3 little errors when I try to compile. Have a class named Grandeur with template D, and then I inherit 3 classes from this one, named Temps(time), Longueur(size), Vitesse(speed), and I am trying to overload the operators such as when I do Temps+Temps->Temps, Vitesse+Vitesse=Vitesse,Longueur+Longueur->Longueur, Longueur/Time->Vitess etc.
In order not to write 3 times the same functions for the operations of same type, I use templates to utilise the genericity. But I have an error when I try to compile. Here is my code:
typedef double Longueur;
typedef double Temps;
typedef double Vitesse;
template<typename D>
class Grandeur {
protected :
double val; const char* unite;
public :
Grandeur(double qqc) : val(qqc) {}
Grandeur(int qqc) : val(qqc) {}
Grandeur(long qqc) : val(qqc) {}
Grandeur(float qqc) : val(qqc) {}
inline friend D operator+ (const D a, const D b) {
return D (a.val + b.val);
}
inline friend D operator- (const D a, const D b) {
return D (a.val - b.val);
}
inline friend double operator* (const D a, const D b) {
return a.val * b.val;
}
inline friend double operator/ (const D a, const D b) {
return a.val / b.val;
}
inline friend D operator* (D a, const int b) {
return D (a.val * b);
}
inline friend D operator/ (const D a, const int b) {
return D (a.val / b);
}
inline friend ostream& operator<< (ostream& os, D d) {
return os << d.val << d.u;
}
class Temps : public Grandeur<Temps> {
public:
};
class Vitesse : public Grandeur<Vitesse> {
public:
};
class Longueur : public Grandeur<Longueur> {
public:
};
};
inline Longueur operator* (const Vitesse v, const Temps t) {
return Longueur(v.val * t.val);
}
inline Vitesse operator/ (const Longueur l, const Temps t) {
return Vitesse(l.val / t.val);
}
inline Temps operator/ (const Longueur l, const Vitesse v) {
return Temps(l.val / v.val);
}
When I try to compile it says:
g++ essai.cc
In file included from essai.cc:4:0:
grandeurs.h:70:58: error: ‘Longueur operator*(Vitesse, Temps)’ must have an argument of class or enumerated type
grandeurs.h:74:58: error: ‘Vitesse operator/(Longueur, Temps)’ must have an argument of class or enumerated type
grandeurs.h:78:58: error: ‘Temps operator/(Longueur, Vitesse)’ must have an argument of class or enumerated type
The lines 70, 74 and 78 are those with the last 3 functions (the inlines). What can I do?

You're declaring the operators at global scope so the types Vitesse etc are not available to the compiler. Why not move the child classes outside Grandeur<T>'s definition?
EDIT for comment:
You're trying to use the operators with double values, but the implicit conversions are not automatically inherited by your child classes. You'll need to define them in each child and pass the parameters up to the parent template class.

Related

How to make a function that is a friend of 2 classes

This is a grossly simplified version of what I am doing but gets the point across. I have 2 classes that can be used for arithmetic. My problem is I want to be able to multiply the 2 together but anyway I try this seems to cause a problem. For example:
class A {
uint32_t val_;
A(uint32_t src) {
val_=src;
}
friend A operator* (const A &a,const B &b); // <------ throws Unknown type B
};
class B {
uint32_t val_;
bool invert_;
B(A src,bool invert) {
val_=src.val_;
invert_=invert;
}
friend A operator* (const A &a,const B &b);
};
A operator* (const A &a,const B &b) {
if (b.invert_) return a.val_/b.val_;
return a.val_*b.val_;
}
how can I get around this seeming recursive error? If it wasn't for the B value always comes second I would put A operator* (const A &a); in the B class so I can just use friend class B in the A class
So the problem is I didn't know the term forward declaration.
class B; //forward declare B
class A {
uint32_t val_;
A(uint32_t src) {
val_=src;
}
friend A operator* (const A &a,const B &b);
};
class B {
uint32_t val_;
bool invert_;
B(A src,bool invert) {
val_=src.val_;
invert_=invert;
}
friend A operator* (const A &a,const B &b);
};
A operator* (const A &a,const B &b) {
if (b.invert_) return a.val_/b.val_;
return a.val_*b.val_;
}
simple fix when you know the term.

Move ADL Friend Declaration

Consider the following class:
template<class a>
class c
{
public:
int x = 0;
// not really templated
friend constexpr auto operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
};
How does one move the function body without declaring it in the outer scope? e.g. pseudo:
template<class a>
friend constexpr auto c<a>::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
The first snippet of OP:
class c
{
public:
int x = 0;
friend constexpr auto operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
};
It shows a free function (operator) that is inline defined in class c as friend.
This is not a member function of class c although it may look so on the first glance.
(If it would be a member function it would be a ternary operator+ but there doesn't exist one in C++ nor can it be overloaded.)
The second snippet of OP:
friend constexpr auto c::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
It is wrong for two reasons:
friend doesn't make sense. (friend to what?)
If it's a free function - scope c:: doesn't make sense.
The friendship of functions cannot be declared outside of the resp. class.
If this would be allowed everybody could declare friendship of functions everywhere which accesses the private members of classes. This would make the sense of private members somehow useless.
(Imagine a safe with an electronic lock and a key pad where the password is written on the door.)
(Original image by Binarysequence - Own work, CC BY-SA 4.0, Link)
Nevertheless, friend functions (and operators) can be defined non-inline, of course.
The following sample shows how:
#include <iostream>
// forward declaration of class c
class c;
// forward declaration of operator +
constexpr auto operator+(int, c const&) noexcept;
// the class c
class c {
// make operator + a friend to grant access to private members
friend constexpr auto operator+(int, c const&) noexcept;
private:
int x;
public:
c() = default;
constexpr c(int x): x(x) { }
int get() const { return x; }
};
// the operator +
constexpr auto operator+(int lhs, c const &rhs) noexcept
{
return c(lhs + rhs.x);
}
// show it in action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(c a(123));
DEBUG(std::cout << (234 + a).get() << '\n');
}
Output:
c a(123);
std::cout << (234 + a).get() << '\n';
357
Live Demo on coliru
This is similar when applied to templates (although the syntax is a bit more tricky):
#include <iostream>
// forward declaration of class c
template <typename T>
class c;
// forward declaration of operator +
template <typename T>
constexpr auto operator+(int, c<T> const&) noexcept;
// the class c
template <typename T>
class c {
friend constexpr auto operator+<>(int, c<T> const&) noexcept;
private:
T x;
public:
c() = default;
constexpr c(T x): x(x) { }
int get() const { return x; }
};
// the operator +
template <typename T>
constexpr auto operator+(int lhs, c<T> const &rhs) noexcept
{
return c(lhs + rhs.x);
}
// show it in action:
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(c<int> a(123));
DEBUG(std::cout << (234 + a).get() << '\n');
}
Output:
c<int> a(123);
std::cout << (234 + a).get() << '\n';
357
Live Demo on coliru
More about inline friend functions:
SO: friend AND inline method, what's the point ?
SO: c++ implementing friend/inline functions (similar question)
SO: Nonmember friend function is always inline (similar question)
The closest you can get is to define the function in a source file such that its out-of-class declaration is not visible to (other) clients. (You would not be able to have its return type be deduced in that case.) In C++20, you can do something very similar by not exporting the friend from a module.
It has been suggested that what you want should be achievable with a differently qualified definition:
constexpr auto ::operator +( int const left,
c const & a ) noexcept
{
return c{ left + x };
}
The otherwise redundant scope resolution operator would cause the definition to “not count” for name lookup, but GCC and Clang currently give it other interpretations: Clang does let ordinary lookup find the function (and issues a warning in the global scope case), while GCC rejects it entirely.

+ operator overload to add different C++ class object

I have seen many example to add objects of same class.I was trying to add two different class objects using operator overloading.
Code:
#include<iostream>
using namespace std;
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( A& m, B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
const A operator+(A& c1,B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}
ostream& operator<<(ostream &os, const A& c)
{
os << c.x;
return os;
}
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( A& m, B& n);
};
int main()
{
A a,u;
B b;
u=a+b;
cout<<"Value of A+B"<<u;
return 0;
}
When i compiled my code it shows Error:
$ g++ operator_overloading.cpp
operator_overloading.cpp: In function ‘const A operator+(A&, B&)’:
operator_overloading.cpp:19:21: error: invalid use of incomplete type ‘struct B’
operator_overloading.cpp:3:7: error: forward declaration of ‘struct B’
What i have done wrong??
The error is clear. You have attempted to use members of B using only a forward declaration.
You have to define the operator after the definition of class B.
For example
#include<iostream>
using namespace std;
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( const A& m, const B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
ostream& operator<<(ostream &os, const A& c)
{
os << c.x;
return os;
}
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( const A& m, const B& n);
};
const A operator+(const A& c1, const B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}
//...
Otherwise the compiler does not know what data members class B has.
Also it is better to define paraneters of the operator as constant references. In this case the operator can deal with temporary objects.
The error message is caused by the fact that you've defined your const A operator+(A& c1,B& c2) before defining the class B.
At this moment B is hence still an incomplete type (meaning you can only use pointers and references to it, but nothing else).
Just move this definition after you've defined B.
The line class B; forward-declares B. This tells the compiler that a class called "B" exists, but nothing else. When you attempt to use c2.y, where c2 is a B, the compiler does not yet know that B even has a y member.
One solution in this case is to move the definition of B so that it appears before the operator+ definition:
class B;
class A
{
public:
int x;
A(int t=99)
{
x=t;
}
friend const A operator+( A& m, B& n);
friend ostream& operator<<(ostream& os, const A& c);
};
class B
{
public:
int y;
B(int e=90)
{
y=e;
}
friend const A operator+( A& m, B& n);
};
const A operator+(A& c1,B& c2)
{
A temp;
temp.x = c1.x + c2.y;
return temp;
}

Operator overloading and inheritance (keeping the same type)

I have a bit of a problem with operator overloading and inheritance in C++.
Quick sketch:
class A {
public:
A operator+ (const A &b) const { ... }
};
class B : public A {
...
};
Now suppose I have two instances of B, x and y. If I add them I will get a thing of type A, however I want it to be of type B.
What is the best way of accomplishing this (aside from reimplementing them in class B) ? CRTP?
You can implement operator+ outside of the class as a template:
template<class type> type operator+(const type& left, const type& right)
{
type toReturn;
toReturn.value = left.value + right.value;
return toReturn;
}
class A {
private:
int value;
template <class type>
friend type operator+<type>(const type& left, const type& right);
};
class B : public A {
};
int main()
{
B test1, test2;
B test3 = test1 + test2;
}
This approach has certain down-sides. The compiler will aggressively try to instantiate the operator+ template for types which you don't want to define operator+, so be aware of that.

Crossing assignment operators?

It's time for my first question now. How do you cross assignments operators between two classes?
class B;
class A {
public:
A &operator = ( const B &b );
friend B &B::operator = ( const A &a ); //compiler error
};
class B {
public:
B &operator = ( const A &a );
friend A &A::operator = ( const B &b );
};
I searched for how to forward declare a member function like:
class B;
B &B::operator = ( const A &a ); //error
But I didn't find anything. And I don't want to make the classes all-out friends with each other. How do I do this?
There is no way to forward-declare member functions. I'm not sure if there is a more elegant way than this to get what you want (I've never had reason to do something like this), but what would work would be to make for the second class a non-member function that is a friend to both classes, and delegate copying to it. Note that operator= cannot be itself a non-member, but something like this should work:
class B;
class A {
public:
A& operator = ( const B &b );
friend B& do_operator_equals ( B& b, const A& b);
};
class B {
public:
B &operator = ( const A &a );
friend A& A::operator = ( const B &b );
friend B& do_operator_equals ( B& b, const A& a);
};
And then in your implementation file
A& A::operator= (const B& b) {
// the actual code to copy a B into an A
return *this;
}
B& B::operator= (const A& a) {
return do_operator_equals(*this, a);
}
B& do_operator_equals(B& b, const A& a) {
// the actual code to copy an A into a B
return b;
}
Edit: Got the A's and B's backwards, oops. Fixed.
The reason for the compiler error is a circular dependency. Each of your operator=() functions require knowledge of the operator=() function inside the other class, so no matter which order you define your classes in, there will always be an error.
Here is one way to sort it out. It isn't very elegant, but it will do what you want:
class A;
class B;
A & set_equal(A & a, const B & b);
B & set_equal(B & a, const A & a);
class A
{
private:
int x;
public:
A & operator=(const B & b) { return set_equal(*this, b); }
friend B & set_equal(B & b, const A & a);
friend A & set_equal(A & a, const B & b);
};
class B
{
private:
int y;
public:
B & operator=(const A & a) { return set_equal(*this, a); }
friend A & set_equal(A & a, const B & b);
friend B & set_equal(B & b, const A & a);
};
A & set_equal(A & a, const B & b) { a.x = b.y; return a; }
B & set_equal(B & b, const A & a) { b.y = a.x; return b; }
You may also be able to solve this problem with inheritance.
edit: here is an example using inheritance. This will work if the copying procedure only needs access to some common data shared by both A and B, which would seem likely if the = operator is to have any meaning at all.
class A;
class B;
class common
{
protected:
int x;
void copyFrom(const common & c) { x = c.x; }
};
class A : public common
{
public:
A & operator=(const common & c) { copyFrom(c); return *this; }
};
class B : public common
{
public:
B & operator=(const common & c) { copyFrom(c); return *this; }
};
Why do you want them to be friends in the first place?
This seem to be impossible the way you write it. The solution would probably be to not have them as friends at all.
You don't forward declare the member function, you forward declare the class.
class B; // DECLARE class B but don't define its contents
class A { // ... uses B as above
};
class B { // ... now you define the class.
};
See the C++ FAQ section 39.