Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Member operators - why the restriction?

93 views
Skip to first unread message

Vir Campestris

unread,
Dec 1, 2020, 7:48:26 AM12/1/20
to
I'm trying to unpick some copy-paste inheritance, and I've just bumped
into a nasty. In three of the copied files there are identical
operator<< and operator>> for a data type which isn't the class - it's
something it holds.

In the fourth one the operator>> and << is different (it's the one
called "Legacy").

What I'd _like_ to do is to have a member operator<< in the base class,
and override it in the legacy one.

But I can't.

Member operator<< can only be for the object itself, not some other type.

Anybody know why?

Andy

Bo Persson

unread,
Dec 1, 2020, 9:25:15 AM12/1/20
to
It's not specific to operator<<, but all member operators are treated as
having an extra 'this' parameter. It's used in overload resolution to
select the proper one to call.

So if you write a member operator<< with two other parameter types, the
compiler will treat it as having 3 parameters.

Non-members will most often come to the rescue here.


Bo Persson

Vir Campestris

unread,
Dec 2, 2020, 12:58:19 PM12/2/20
to
On 01/12/2020 14:24, Bo Persson wrote:
> So if you write a member operator<< with two other parameter types, the
> compiler will treat it as having 3 parameters.

... and then refuse to compile it because it is only allowed to have two
parameters, not three :(

You can't even make it a static member.

Andy

Bonita Montero

unread,
Dec 2, 2020, 1:15:11 PM12/2/20
to
There are two things you must be aware if you define member-operators:
1. The operator only applies to objects of the defined class and its
descendants and not convertible classes.
2. With external operators you can attach semantics to a class like
if you would have defined a member-operator.

Vir Campestris

unread,
Dec 4, 2020, 3:59:38 PM12/4/20
to
Yes, but why?

I want to have operators for internal data types within a class whose
behaviour varies depending on the class.

Andy

Öö Tiib

unread,
Dec 4, 2020, 6:46:18 PM12/4/20
to
Can you post brief example of what you want to do and why
non-member operators can not help?

Bonita Montero

unread,
Dec 5, 2020, 2:52:14 AM12/5/20
to
>> There are two things you must be aware if you define member-operators:
>> 1. The operator only applies to objects of the defined class and its
>>     descendants and not convertible classes.
>> 2. With external operators you can attach semantics to a class like
>>     if you would have defined a member-operator.

> Yes, but why?

Because the operators are symmetrical if you define them externally.
Defined internally only the right part can be a non-descendant which
is converted to the proper type.

Vir Campestris

unread,
Dec 7, 2020, 4:34:09 PM12/7/20
to
struct A {
std::string to_string();
};
struct XML {
A a;
std::ostream& operator<<(std::ostream& os, A const& datum) { os
<< "<A>" << a.to_string() << "</A>" ; }
};
struct JSON {
A a;
std::ostream& operator<<(std::ostream& os, A const& datum) { os
<< "{\"A\":\"" << a.to_string() << "\"}" }
};

Within the struct XML an A should be written in XML format; within JSON
it should be written in JSON format.

(The actual differences are more subtle, and there are 4 classes
containing many different data types)

With non-member operators they are shared. I have a workaround; declare
the operators in a namespace, and add "using ns;" in each class.

Andy

Öö Tiib

unread,
Dec 7, 2020, 5:29:44 PM12/7/20
to
These accept argument "datum" but output member "a"? I assume
typo.

> (The actual differences are more subtle, and there are 4 classes
> containing many different data types)
>
> With non-member operators they are shared. I have a workaround; declare
> the operators in a namespace, and add "using ns;" in each class.

Ok. Seems lucky case where you do not need member's
names ... and class name is plenty.

Tim Woodall

unread,
Dec 8, 2020, 2:50:25 AM12/8/20
to
On 2020-12-07, Vir Campestris <vir.cam...@invalid.invalid> wrote:
>
> struct A {
> std::string to_string();
> };
> struct XML {
> A a;
> std::ostream& operator<<(std::ostream& os, A const& datum) { os
><< "<A>" << a.to_string() << "</A>" ; }
> };
> struct JSON {
> A a;
> std::ostream& operator<<(std::ostream& os, A const& datum) { os
><< "{\"A\":\"" << a.to_string() << "\"}" }
> };
>
> Within the struct XML an A should be written in XML format; within JSON
> it should be written in JSON format.
>
How can this possibly work? Consider:

template<typename T> void do_stuff(const T& X)
{
const A& a = T.a;
print(a); //Which does '<< a' in a different translation unit
}

Can you do something like?

struct XML {
struct T : public A {};
T a;
std::ostream& operator<<(std::ostream& os, T const& datum) { os << "<A>" << a.to_string() << "</A>" ; }
};
struct JSON {
struct T : public A {};
T a;
std::ostream& operator<<(std::ostream& os, T const& datum) { os << "{\"A\":\"" << a.to_string() << "\"}" }
};

Now you have JSON::T and XML::T that are different types but you can
keep all the code in struct A {}


Bonita Montero

unread,
Dec 8, 2020, 9:12:22 AM12/8/20
to
> struct XML {
>         A a;
>         std::ostream& operator<<(std::ostream& os, A const& datum) { os
> << "<A>" << a.to_string() << "</A>" ; }
> };
> struct JSON {
>         A a;
>         std::ostream& operator<<(std::ostream& os, A const& datum) { os
> << "{\"A\":\"" << a.to_string() << "\"}"  }
> };

You can't define operators with two parameters inside a class.
They have to be global and for your purpose they might be friend
of a class.

Tim Woodall

unread,
Dec 8, 2020, 3:10:29 PM12/8/20
to
(Obviously the operator<< need to be moved outside the class and XML::
type qualifiers added but I think the idea is clear...)

Vir Campestris

unread,
Dec 8, 2020, 5:22:27 PM12/8/20
to
Seems to me you hit exactly the same problem I did: you can't define an
operator<< within a class to serialise an arbitrary type, only to
serialise the containing class (and on further experimentation I can't
see what use it is, you have to write object << std::cout)

But you've given me an idea...

struct A {
std::string to_string() const { std::ostringstream s; s <<
"this A is at " << this; return s.str();}
};

struct XML {
struct XML_A: public A {
} a;
};
std::ostream& operator<<(std::ostream& os, XML::XML_A const & a) { os <<
"<A>" << a.to_string() << "</A>" ; return os;}
std::ostream& operator<<(std::ostream& os, XML const & x){ os << x.a;
return os;}

struct JSON {
struct JSON_A: public A {
} a,b;
};
std::ostream& operator<<(std::ostream& os, JSON::JSON_A const & a) { os
<< "{\"A\":\"" << a.to_string() << "\"}"; return os;}
std::ostream& operator<<(std::ostream& os, JSON const & j){ os << j.a <<
j.b; return os;}

Darnn it's ugly.

Andy

Vir Campestris

unread,
Dec 8, 2020, 5:23:08 PM12/8/20
to
On 08/12/2020 14:11, Bonita Montero wrote:
> You can't define operators with two parameters inside a class.
> They have to be global and for your purpose they might be friend
> of a class.

Read the thread again. Including the title.

Andy

Tim Woodall

unread,
Dec 9, 2020, 5:10:24 AM12/9/20
to
:-) I wish I was better at communicating... your idea is exactly what I
was trying to communicate (except that I was suggesting using XML::T and
JSON::T rather than XML::XML_A and JSON::JSON_A)

Bonita Montero

unread,
Dec 9, 2020, 6:37:04 AM12/9/20
to
>> You can't define operators with two parameters inside a class.
>> They have to be global and for your purpose they might be friend
>> of a class.

> Read the thread again. Including the title.

I don't have to read again. A two parameter member-operator includes
the object as the left operand. So you can' define a member operator
with two parameters inside the class.

Bonita Montero

unread,
Dec 9, 2020, 6:41:08 AM12/9/20
to
> Darnn it's ugly.

No that's not ugly since you can extend the operators acting on a class
without modifying the class. the io_manip-objects work that way. And a
further advantage is, that both objects can be of converted objects, so
this operators bekome symmetrical in that way.
If you want a member-operator, define the member-operator with one
operand and you get what you want.

Vir Campestris

unread,
Dec 10, 2020, 4:08:10 PM12/10/20
to
And your answer to "Why the restriction?" is...

Öö Tiib

unread,
Dec 10, 2020, 4:54:28 PM12/10/20
to
I suspect it is not restriction but syntax how free operators and member
operators are declared. Member operators have first hidden parameter
as this like member functions have first hidden parameter as this. Type
of operators what you want is not part of language. It could be added
like for example static member operators ... but no one has seemingly
pushed such ideas hard enough.

Bonita Montero

unread,
Dec 11, 2020, 3:41:09 AM12/11/20
to
>> I don't have to read again. A two parameter member-operator includes
>> the object as the left operand. So you can' define a member operator
>> with two parameters inside the class.

> And your answer to "Why the restriction?" is...

Because there's another place where to define such operators: globally.
0 new messages