Which operators cannot be overloaded and why not?

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Sep 14 17:13:06 UTC 2021


On Mon, Sep 13, 2021 at 06:19:20PM +0000, NonNull via Digitalmars-d-learn wrote:
> On Monday, 13 September 2021 at 16:12:34 UTC, H. S. Teoh wrote:
> > On Mon, Sep 13, 2021 at 02:12:36PM +0000, NonNull via
> > Digitalmars-d-learn wrote:
> > > Which operators cannot be overloaded and why not?
> > 
> > Others have already given the list, so I won't repeat that.
> 
> I didn't see unary &. Maybe others are missing.
[...]

IIRC, unary & cannot be overloaded for the same reasons &&, ||, and !
cannot be overloaded: it leads to hard-to-understand, hard-to-maintain
code.  Incidentally, C++ *does* allow overloading of &, ostensibly
because some wrapper types might want to use it to become transparent.
But one of the consequences of this is that now you need a
std::address-of pseudo-operator that *actually* takes an address of
something when you *really* mean to take the address of the wrapper
object instead of the wrapped object.  So & loses its original meaning
and has to be replaced by a std:: hack.  Which, to me, is abundant proof
that overloading & was a bad idea in the first place.

//

BTW, as an aside, as a example of why every-man-for-himself,
wild-wild-west operator overloading in C++ is a bad idea, consider these
two lines of C++ code:

	fun<A, B>(a, b);
	gun<T, U>(a, b);

What do they mean?  Ostensibly, these are function calls to two template
functions, specifying explicit template arguments.  Unfortunately, that
is not the case: only *one* of these lines is a template function call,
the other is something else altogether.  But nobody can tell the
difference unless they read the entire context, as shown below.
(Incidentally, this example also shows why C++'s choice of template
syntax was a poor one.) Compile and run with a C++ compiler to find out
what the actual behaviour is.


-------
// Totally evil example of why C++ template syntax and free-for-all
// operator overloading is a Bad, Bad Idea.
#include <iostream>

struct Bad { };
struct B { };
struct A {
	Bad operator,(B b) { return Bad(); }
};
struct D { };
struct Ugly {
	D operator>(Bad b) { return D(); }
} U;
struct Terrible { } T;
struct Evil {
	~Evil() {
		std::cout << "Hard drive reformatted." << std::endl;
	}
};
struct Nasty {
	Evil operator,(D d) { return Evil(); }
};
struct Idea {
	void operator()(A a, B b) {
		std::cout << "Good idea, data saved." << std::endl;
	}
	Nasty operator<(Terrible t) { return Nasty(); }
} gun;

template<typename T, typename U>
void fun(A a, B b) {
	std::cout << "Have fun!" << std::endl;
}

int main() {
	A a;
	B b;

	// What do these lines do?
	fun<A, B>(a, b);
	gun<T, U>(a, b);
}
-------


T

-- 
Your inconsistency is the only consistent thing about you! -- KD


More information about the Digitalmars-d-learn mailing list