473,406 Members | 2,259 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

How to reuse a friend operator?


Hello,

is it possible to reuse a friend operator which is defined
inside a class? I'd like to obtain the following behaviour:

class integer {

[...]

integer operator +(signed long int v) const {

// It somehow does its job
}

friend inline integer operator +(signed long int lhs, const integer&
rhs) {

return rhs.operator +(lhs); // This is allowed because of
commutativity
}

friend inline integer operator +(signed int lhs, const integer& rhs) {

return operator +(static_cast<signed long int>(lhs),rhs); // Here's
the problem
}
};
integer i;
i + 10; // the first operator is used
10L + i; // the second operator is used
10 + i; // the third is used and then control is passed to the second one
The problem is that the compiler (G++ 3.4) doesn't see the operators
declared as friends. It displays a message that no operator can be matched
and shows the list of alternatives, but only local operators are listed (in
this example there's only one, in the real project there are 6). When the
friend operators are declared in a standard way, i.e. outside of the class,
everything works OK. So the question is: how to qualify the "operator +()"
in the third operator's body to use the second one? None of these
ad hoc approaches works:

"return ::operator +("
"return integer::operator +("
"return friend operator +("

Best regards
Piotr Wyderski

Jul 22 '05 #1
10 2276
On Thu, 22 Jul 2004 17:22:12 -0700, Piotr Wyderski wrote:
Hello,

is it possible to reuse a friend operator which is defined inside a
class? I'd like to obtain the following behaviour:

class integer {

[...]

integer operator +(signed long int v) const {

// It somehow does its job
}

friend inline integer operator +(signed long int lhs, const
integer&
rhs) {

return rhs.operator +(lhs); // This is allowed because of
commutativity
}

friend inline integer operator +(signed int lhs, const integer&
rhs) {

return operator +(static_cast<signed long int>(lhs),rhs); //
Here's
the problem
}
};
integer i;
i + 10; // the first operator is used 10L + i; // the second operator is
used 10 + i; // the third is used and then control is passed to the
second one


If the problem that you are trying to solve is adding an integer to a
class either on the left or on the right hand side, the following is
the traditional way of doing that:

#include <iostream>

using namespace std;

class Integer
{
long value_;

friend ostream & operator<< (ostream &, Integer const &);

public:

Integer(long value = 0)
:
value_(value)
{}

Integer & operator+= (Integer const & rhs)
{
value_ += rhs.value_;
return *this;
}
};

Integer operator+ (Integer const & lhs, Integer const & rhs)
{
Integer sum = lhs;
sum += rhs;
return sum;
}

ostream & operator<< (ostream & os, Integer const & i)
{
return os << i.value_;
}

int main()
{
Integer i(42);
cout << (i + 10) << '\n'
<< (10L + i) << '\n'
<< (10 + i) << '\n'
<< (i + Integer(10)) << '\n';
}

Ali
Jul 22 '05 #2

Ali Cehreli wrote:
If the problem that you are trying to solve is adding an integer to a
class either on the left or on the right hand side, the following is
the traditional way of doing that:


No, the problem is not the question how to add an integer to a class.
This way is very inefficient in this particular case, because it requires
a temporary object, which is quite big here. I have a very efficient
implementation of such operators and I want to use it. The problem
is that when the friend operators are defined inside the "integer" class,
the compiler doesn't allow to use another friend operator to implement
the current one. When they are defined outside the class, it works.
My question is: why does the compiler behave like that and how to
get rid of this problem without moving the operators outside?
Nobody knows? Have I found a hole in C++?

Jul 22 '05 #3

Ali Cehreli wrote:

Never mind, I have just found a solution, so EOT.

Jul 22 '05 #4
"Piotr Wyderski" <wy************@ii.uni.wroc.pl> wrote...

Ali Cehreli wrote:
If the problem that you are trying to solve is adding an integer to a
class either on the left or on the right hand side, the following is
the traditional way of doing that:


No, the problem is not the question how to add an integer to a class.
This way is very inefficient in this particular case, because it requires
a temporary object, which is quite big here. I have a very efficient
implementation of such operators and I want to use it. The problem
is that when the friend operators are defined inside the "integer" class,
the compiler doesn't allow to use another friend operator to implement
the current one. When they are defined outside the class, it works.
My question is: why does the compiler behave like that and how to
get rid of this problem without moving the operators outside?
Nobody knows? Have I found a hole in C++?


No, you have more likely found a bug in your compiler. This should
work, at least according to 3.4.1/9:
---------
struct A {
friend int operator +(int, A) { return 42; }
operator double() const { return (2 + *this) / 10.; }
// ^^^^^^^^^ operator+ is used
operator float() const { return operator+(5,A()) / 5.f; }
// ^^^^^^^^^^ should also be found
// during name lookup.
};

#include <iostream>

int main() {
A a;
double d = a;
std::cout << d << std::endl; // should print 4.2
}
--------
The code compiles fine with Comeau C++.

Victor
Jul 22 '05 #5

Victor Bazarov wrote:
The code compiles fine with Comeau C++.


But consider this one, which is a simplified version of my problem:
-----------8<-------------

#include <iostream>
class X {

public:

int v;

int operator +(const int R) {

return 3;
}

friend inline int operator +(const int L, const X& R) {

std::cout << "OK int";
return L;
}

friend inline int operator +(const char L, const X& R) {

std::cout << "OK char";
return operator +(static_cast<int>(L),R); // (*)
}
};

int main(int argc, char *argv[]) {

X x;
'a'+x;
return 0;
}
-----------8<-------------

Desired behaviour is that the program displays "OK charOK int"

GPP 3.4 displays:

test.cpp: In function `int operator+(char, const X&)':
test.cpp:24: error: no matching function for call to `X::operator+(int,
const X&)'
test.cpp:10: note: candidates are: int X::operator+(int)

If I change the (*) line to

return ::operator +(static_cast<int>(L),R);

then it works. VC7.1 in all cases reports an error:

error C3767: '+' matching function is not accessible
could be the friend function at 'vcadv.cpp(19)' : '+' [may be found via
argument-dependent lookup]

or the friend function at 'vcadv.cpp(25)' : '+' [may be found via
argument-dependent lookup]

Comeau on-line tester says:

error: the global scope has no "operator+"
return ::operator +(static_cast<int>(L),R);
^

When I remove "::", it says:

error: a nonstatic member reference must be relative to a
specific object
return operator +(static_cast<int>(L),R);

So which behaviour is correct according to the C++ standard? :-)

Best regards
Piotr Wyderski
Jul 22 '05 #6
"Piotr Wyderski" <wy************@ii.uni.wroc.pl> wrote...

Victor Bazarov wrote:
The code compiles fine with Comeau C++.


But consider this one, which is a simplified version of my problem:
-----------8<-------------

#include <iostream>
class X {

public:

int v;

int operator +(const int R) {

return 3;
}

friend inline int operator +(const int L, const X& R) {

std::cout << "OK int";
return L;
}

friend inline int operator +(const char L, const X& R) {

std::cout << "OK char";
return operator +(static_cast<int>(L),R); // (*)
}
};

int main(int argc, char *argv[]) {

X x;
'a'+x;
return 0;
}
-----------8<-------------

Desired behaviour is that the program displays "OK charOK int"

GPP 3.4 displays:

test.cpp: In function `int operator+(char, const X&)':
test.cpp:24: error: no matching function for call to `X::operator+(int,
const X&)'
test.cpp:10: note: candidates are: int X::operator+(int)

If I change the (*) line to

return ::operator +(static_cast<int>(L),R);

then it works. VC7.1 in all cases reports an error:

error C3767: '+' matching function is not accessible
could be the friend function at 'vcadv.cpp(19)' : '+' [may be found via
argument-dependent lookup]

or the friend function at 'vcadv.cpp(25)' : '+' [may be found via
argument-dependent lookup]

Comeau on-line tester says:

error: the global scope has no "operator+"
return ::operator +(static_cast<int>(L),R);
^

When I remove "::", it says:

error: a nonstatic member reference must be relative to a
specific object
return operator +(static_cast<int>(L),R);

So which behaviour is correct according to the C++ standard? :-)


Good question.

Name lookup is a complicated issue to say the least.

As I read it, the Standard, 3.4.3/2, the last part of it, says that
if during an ordinary unqualified name lookup a _member_ is found,
then the associated namespaces namespaces and classes are not considered.

Since your class has a member operator+, the rest of operators+ are not
found.

So, it is standard behaviour, there are work-arounds, do you want me to
help you with them or do you already know them?

Victor
Jul 22 '05 #7
Piotr Wyderski wrote:

Victor Bazarov wrote:
The code compiles fine with Comeau C++.


But consider this one, which is a simplified version of my problem:

-----------8<-------------

#include <iostream>

class X {

public:

int v;

int operator +(const int R) {

return 3;
}

friend inline int operator +(const int L, const X& R) {

std::cout << "OK int";
return L;
}

friend inline int operator +(const char L, const X& R) {

std::cout << "OK char";
return operator +(static_cast<int>(L),R); // (*)
}
};

int main(int argc, char *argv[]) {

X x;
'a'+x;
return 0;
}

-----------8<-------------

Desired behaviour is that the program displays "OK charOK int"

GPP 3.4 displays:

test.cpp: In function `int operator+(char, const X&)':
test.cpp:24: error: no matching function for call to `X::operator+(int,
const X&)'
test.cpp:10: note: candidates are: int X::operator+(int)

If I change the (*) line to

return ::operator +(static_cast<int>(L),R);

then it works. VC7.1 in all cases reports an error:

error C3767: '+' matching function is not accessible
could be the friend function at 'vcadv.cpp(19)' : '+' [may be found via
argument-dependent lookup]

or the friend function at 'vcadv.cpp(25)' : '+' [may be found via
argument-dependent lookup]

Comeau on-line tester says:

error: the global scope has no "operator+"
return ::operator +(static_cast<int>(L),R);
^

When I remove "::", it says:

error: a nonstatic member reference must be relative to a
specific object
return operator +(static_cast<int>(L),R);

So which behaviour is correct according to the C++ standard? :-)

Best regards
Piotr Wyderski


Here is my take on it:

The scope resolution operator :: in the line (*) is needed because
without it a member function
int operator +(const int R)
is found, and the global scope is not considered. The reason why
the class scope takes precedence over the global scope is that the
friend function is defined inside the class (see 11.4/5).

So, unless you remove the member operator+ or move the definition
of the friend operators outside of the class definition, you have
to use the operator ::.

Now, it appears that Comeau cannot find a friend function in
the global scope unless this function is also declared in the
global scope, and I /think/ it is right (3.4.3/4). Gcc seems to
let you get away without a global declaration.

A few forward declarations just before the class defintion should
help:
class X;
int operator +(char L, const X& R); //lose the superfluous "const"
int operator +(int L, const X& R); //ditto

(now it compiles with both Gcc and Comeau).

Denis
Jul 22 '05 #8

Denis Remezov wrote:
The scope resolution operator :: in the line (*) is needed because
without it a member function
int operator +(const int R)
is found, and the global scope is not considered.
Right, but why does VC reject it?
So, unless you remove the member operator+ or move the definition
of the friend operators outside of the class definition, you have
to use the operator ::.
If it were the standard solution, it would be perfectly OK. But
the two mentioned compilers refuse to accept this syntax. And
I don't know which one is right... :-)
A few forward declarations just before the class defintion should help:


Yes, but it is not better than moving the friend operators outside.
So, is it possible to keep internal friend operators without adding
anything outside the class (scope qualifiers inside of it are OK)?
It's a matter of honour, heh, because we don't want the standard
to be holey, do we? ;-)

Best regards
Piotr Wyderski

Jul 22 '05 #9

Victor Bazarov wrote:
As I read it, the Standard, 3.4.3/2, the last part of it, says that
if during an ordinary unqualified name lookup a _member_ is found,
then the associated namespaces namespaces and classes are not considered.
I'll look closer at that chapter.
So, it is standard behaviour, there are work-arounds, do you want me to
help you with them or do you already know them?


Well, of course, please describe the workarounds you know, maybe
something would be new to me. However, the question is not how to
fix it, becaue the most standard-conforming workaround is to move
friends outside the class. The question is how to do it using internal
friends, because:

a) the C++ standard allows internal friends;
b) it seems to be impossible to call one of them from another.

If the above statement is true, then there is an imperfection
in the name lookup algorithm and it should be fixed.

Best regards
Piotr Wyderski

Jul 22 '05 #10
"Piotr Wyderski" <wy************@ii.uni.wroc.pl> wrote...

Victor Bazarov wrote:
As I read it, the Standard, 3.4.3/2, the last part of it, says that
if during an ordinary unqualified name lookup a _member_ is found,
then the associated namespaces namespaces and classes are not
considered.
I'll look closer at that chapter.
So, it is standard behaviour, there are work-arounds, do you want me to
help you with them or do you already know them?
Well, of course, please describe the workarounds you know, maybe
something would be new to me. However, the question is not how to


If it not, then I won't bother.
fix it, becaue the most standard-conforming workaround is to move
friends outside the class. The question is how to do it using internal
friends, because:

a) the C++ standard allows internal friends;
b) it seems to be impossible to call one of them from another.
That's not necessarily true. The thing is that the member operator+
_interferes_ with name lookup of the friend.

If the above statement is true, then there is an imperfection
in the name lookup algorithm and it should be fixed.


Try describing the problem in comp.std.c++, and possibly suggest the
fix after studying the current behaviour in more detail.

Victor
Jul 22 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Nitin Bhardwaj | last post by:
Thanx in advance for the response... I wanna enquire ( as it is asked many a times in Interviews that i face as an Engg PostGraduate ) about the overloading capability of the C++ Language. ...
6
by: Ben Ingram | last post by:
Hi all, I am writing a template matrix class in which the template parameters are the number of rows and number of columns. There are a number of reasons why this is an appropriate tradeoff for...
6
by: Adam Parkin | last post by:
Hello, all I'm having a problem with friend functions in a templatized Queue class I'm writing using linked lists. The problem is that I can't get the friend function to be able to access private...
5
by: Srini nandiraju | last post by:
Hi folks, I am trying to implement a friend class and the following is what I did. Please scroll down. /***************** CODE **********************************/ class BKP { private: int...
5
by: Ruben Campos | last post by:
Some questions about this code: template <typename T> class MyTemplate; template <typename T> MyTemplate <T> operator- (const MyTemplate <T> & object); template <typename T> MyTemplate <T>...
5
by: Teddy | last post by:
Hello all consider the class Date declaretion below: class Date { public: Date(); Date(int year, int month, int day); Date(const string&); int getYear() const;
4
by: Amadeus W. M. | last post by:
What is the difference between friend ostream & operator<<(ostream & OUT, const Foo & f){ // output f return OUT; } and template <class X>
9
by: wo3kie | last post by:
#include <iostream> #include <map> #include <utility> // // Base // / | \ // Derived1 Derived2 \ // \ | / // Derived3
5
by: Daniel T. | last post by:
The goal is to make a friend function of an inner template class... template < typename T > class Foo { public: class Bar { friend bool operator==( const typename Foo<T>::Bar& lhs, const...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.