Why doesn't my overloaded comma operator get called? - c++

I'm trying to overload the comma operator with a non-friend non-member function like this:
#include <iostream>
using std::cout;
using std::endl;
class comma_op
{
int val;
public:
void operator,(const float &rhs)
{
cout << this->val << ", " << rhs << endl;
}
};
void operator,(const float &lhs, const comma_op &rhs)
{
cout << "Reached!\n"; // this gets printed though
rhs, lhs; // reversing this leads to a infinite recursion ;)
}
int main()
{
comma_op obj;
12.5f, obj;
return 0;
}
Basically, I'm trying to get the comma operator usable from both sides, with a float. Having a member function only allows me to write obj, float_val, while having an additional helper non-friend non-member function allows me to write float_val, obj; but the member operator function doesn't get called.
GCC cries:
comma.cpp: In function ‘void operator,(const float&, const comma_op&)’:
comma.cpp:19: warning: left-hand operand of comma has no effect
comma.cpp:19: warning: right-hand operand of comma has no effect
Note:
I realise that overloading operators, that too to overload comma op., Is confusing and is not at all advisable from a purist's viewpoint. I'm just learning C++ nuances here.

void operator,(const float &rhs)
You need a const here.
void operator,(const float &rhs) const {
cout << this->val << ", " << rhs << endl;
}
The reason is because
rhs, lhs
will call
rhs.operator,(lhs)
Since rhs is a const comma_op&, the method must be a const method. But you only provide a non-const operator,, so the default definition will be used.

Related

Error when using operator << with implicitly converted non-fundamental data types [duplicate]

This question already has answers here:
Overload resolution failure when streaming object via implicit conversion to string
(5 answers)
Closed 4 years ago.
I have a struct that works as a wrapper for other types as follows:
template<typename T>
struct A {
A& operator=(const T& value){
m_value = value;
return *this;
}
operator T() const {
return m_value;
}
private:
T m_value;
};
I use it like this:
int main() {
A<int> a;
a = 5; // Copy assignment constructor
std::cout << a << "\n"; // Implicit conversion to int
}
which works as expected. My problem occurs when using non-fundamental types as the following example shows:
int main() {
A<std::complex<int>> c;
c = std::complex<int>(2, 2);
std::cout << c << "\n";
}
The snippet above raises an invalid operands to binary expression error.
Why does this error occur? Why isn't the overloaded operator << of std::complex<int> used with the implicitly converted A<std::complex<int>>?
The stream operators for std::complex are template functions. They will not be invoked unless you actual have a std::complex as no conversions happens in template argument deduction. This means the compiler will not find a suitable overload to print a A<std::complex<int>>
You're first case for works because std::basic_ostream::operator << is overloaded to take an int and you are allowed one user defined conversion is overload resolution.
As a work arround you can define your own operator << that takes your wrapper and forward to the underlying types' operator <<. That would look like
template<typename T>
std::ostream& operator <<(std::ostream& os, const A<T>& a)
{
return os << static_cast<T>(a);
}

How does an operator inside a class work?

class A {
public:
string operator+( const A& rhs ) {
return "this and A&";
}
};
string operator+( const A& lhs, const A& rhs ) {
return "A& and A&";
}
string operator-( const A& lhs, const A& rhs ) {
return "A& and A&";
}
int main() {
A a;
cout << "a+a = " << a + a << endl;
cout << "a-a = " << a - a << endl;
return 0;
}
//output
a+a = this and A&
a-a = A& and A&
I'm curious as to why the operator inside the class gets to be called rather than the outside one. Is there some sort of priority among operators?
The process of selecting amongst several functions of the same name is called overload resolution. In this code, the member is preferred because the non-member requires a qualification conversion (adding const to lhs) but the member does not. If you made the member function const (which you should, since it does not modify *this) then it would be ambiguous.
Whenever your object is non-const there's a priority of non-constness over constness. The inner will be called when the left side is non-const, and the outer will be called when the left side is const.
See what happens when the inner is defined as:
string operator+( const A& rhs ) const;

Weird operator overloading, "operator T& () const noexcept { return *_ptr; }"

I studied that the format of operator functions is
(return value)operator[space]op(arguments){implementation}
But, In std::reference_wrapper implementation, there is an operator overloading function declared as operator T& () const noexcept { return *_ptr; }.
Is this operator different from T& operator () const noexcept { return *_ptr; } ?. If both are different, then what is the use of the first?
operator T& () const noexcept; is a user-defined conversion function. std::reference_wrapper has it in order to give you access to the stored reference, without changing the syntax:
int x = 42;
int &a = x;
std::reference_wrapper<int> b = x;
std::cout << a << " " << b << std::endl;
Assignment is a little bit trickier.
T& operator () const noexcept; is an attempt to declare operator(), but fails to compile due to missing parameter list. The right syntax would be:
T& operator ()( ) const noexcept;
// ^
// parameters here
and the usage is completely different.

Override operators with a left and right parameter

I have the simple setup:
#include<iostream>
class Stuff {};
ostream &operator<<(ostream &lhs, const Stuff &rhs) {
return lhs << "something";
}
int main() {
Stuff stuff;
cout << stuff << endl;
cin.get();
}
where the operator<< function prints the mockup Stuff class to an ostream. What I would like to do though is move that function into the Stuff class itself. As in:
class Stuff {
ostream &operator<<(ostream &lhs, const Stuff &rhs) {
return lhs << "something";
}
};
For the life of me though, I can't figure out how to get this to work. I get the sense that I'm trying to re-define a left associative operator from the right side. Is there any way to do this properly?
The way you've defined it, that function would be a member of Stuff, so if it was allowed in C++ you'd have to call it like this:
Stuff stuff;
stuff.operator<<(std::cout, stuff);
So you don't want that.
A binary operator (like <<) takes two arguments (called operands). If it's a (non-static) member function then it must be a member function taking one parameter, where the left operand is the object that you call the function on, and the right operand is the function parameter. So you could do this:
struct Stuff {
std::ostream& operator<<(std::ostream& o) { return o << something; }
};
Stuff s;
s << std::cout << std::endl;
But you probably don't want that either!
To write std::cout << s the operator must either be a member of the left operand or must be a non-member function, so you cannot make it a member of Stuff.
Maybe what you're trying to do is this:
class Stuff {
friend std::ostream& operator<<(std::ostream& lhs, const Stuff& rhs) {
return lhs << "something";
}
};
A friend function is not a member function, so this is valid.

C++ operator overloading affect in-class operator functions

What if i overload the != operator and use class!= inside one of other operator overloaders, does it accept it as non-overloaded or overloaded? I am trying to create a noob_ptr (a kind of custom-pointer wraper i am thinking of)
class noob_ptr
{
private: //does this change the behaviour? public? protected?
bool operator!=(noob_ptr x)
{
...
}
bool operator,(noob_ptr y)
{
...
if(y!=z)...
...
}
...
}
Does below example cancel usage of overloaded-operator in my class?
class noob_ptr
{
protected: //or public
bool operator,(noob_ptr y) //yes, z is also a noob_ptr
{
...
if(y!=z)...
...
}
...
private:
bool operator!=(noob_ptr x)
{
...
}
}
If type of z is also a noob_ptr, then the answer is YES, it will call the overloaded operator != for your class.
Also, I'd suggest you this comparison method signature:
bool operator != (const noob_ptr& x) const;
so it can be used for constant pointers and also avoid object copying while calling the overloaded operator.
UPD: If you declare operator != as private, then it'll be available in all member functions of noob_ptr class, friend classes and functions of noob_ptr class, and for all other usages will result in a compilation error with a message like: "operator != is inaccessible due to its protection level"
If the operands you supply are ones for which the language's built-in != will work, then that's what gets used. If they're of user-defined types, then it'll search for a user-defined operator!= that's defined for those types (or some types that support implicit conversion from those types).
C++ will always use the "best match" which is the closest in qualifiers, access specifiers such as private, scope, namespace, etc.
So, if there is a global namespace operator!= and a class one (that lacks the left-hand-side argument which is assumed to be the class& or const class& if the method is const -- which it should be), then inside the class (namespace) you will get the one inside the class.
If there is only one between the global namespace and the class, you will obviously get that one.
The following code demonstrates between global and class scope. You can extend this by adding const qualifiers, etc.
#include <iostream>
using namespace std;
// Forward declaration to use without the class definition
class X;
bool operator!=( int lhs, const X& rhs) {
cout << "bool operator!=( int lhs, const X& rhs)" << endl;
return false;
}
bool operator!=(const X& lhs, const X& rhs) {
cout << "bool operator!=(const X& lhs, const X& rhs)" << endl;
return false;
}
bool operator!=(const X& lhs, int rhs) {
cout << "bool operator!=(const X& lhs, int rhs)" << endl;
return false;
}
// Note: Can't do: bool operator!=(int lhs, int rhs) -- already defined
class X {
private:
int x;
public:
X(int value) : x(value) { }
bool operator !=(const X& rhs) {
cout << "bool X::operator !=(const X& rhs)" << endl;
return true;
}
bool operator !=(int rhs) {
cout << "bool X::operator !=(int rhs)" << endl;
return true;
}
void f() {
X compare(1);
cout << "X::f()" << endl;
cout << (5 != 3) << endl; // Uses built-in
cout << (*this != 3) << endl; // Uses member function
cout << (*this != 1) << endl; // Uses member function
cout << (1 != *this) << endl; // There can be no member function, uses global namespace
cout << (*this != compare) << endl;
}
};
void f(const X& arg) {
cout << "f()" << endl;
X compare(1);
cout << (5 != 3) << endl; // Uses built in
cout << (arg != 3) << endl; // Uses global namespace
cout << (arg != 1) << endl; // Uses global namespace
cout << (1 != arg) << endl; // Uses global namespace
cout << (arg != compare) << endl; // Uses global namespace
}
int main(int argc, char **argv) {
X x(1);
x.f();
f(x);
return 0;
}