Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Compiler error with friend (http://www.velocityreviews.com/forums/t741961-compiler-error-with-friend.html)

Adrian 01-13-2011 03:26 PM

Compiler error with friend
 
Hi Guys,

I obviously have a mistake in this - I just cant seem to see it for
looking this morning.

I've tried various forms of the friend declaration but the compiler
seems to be ignoring them all.

Why wont the following compile when using namespaces

TIA

Adrian

adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
foo.cc:18:12: warning: unused parameter 'os'
foo.cc:32:5: warning: unused parameter 'argc'
foo.cc:32:5: warning: unused parameter 'argv'

adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
-Weffc++ foo.cc
foo.cc:18:12: warning: unused parameter 'os'
foo.cc:32:5: warning: unused parameter 'argc'
foo.cc:32:5: warning: unused parameter 'argv'
foo.cc: In function 'std::ostream& operator<<(std::ostream&, const
level1::level2::foo&)':
foo.cc:18:12: error: 'void level1::level2::foo::print(std::ostream&)
const' is private
foo.cc:43:16: error: within this context



#include <iostream>

#ifdef NAMESPACES
namespace level1
{
namespace level2
{
#endif
class foo
{
public:
#ifdef NAMESPACES
friend std::ostream &operator<<(std::ostream &os, const
::level1::level2::foo &rhs);
#else
friend std::ostream &operator<<(std::ostream &os, const foo &rhs);
#endif
private:
void print(std::ostream &os) const
{
}
};
#ifdef NAMESPACES
}}
#endif

#ifdef NAMESPACES
std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs);
#else
std::ostream &operator<<(std::ostream &os, const foo &rhs);
#endif

int main(int argc, char *argv[])
{
return 0;
}

#ifdef NAMESPACES
std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs)
#else
std::ostream &operator<<(std::ostream &os, const foo &rhs)
#endif
{
rhs.print(os);
return os;
}

Kevin P. Fleming 01-13-2011 03:34 PM

Re: Compiler error with friend
 
On 01/13/2011 09:26 AM, Adrian wrote:
> Hi Guys,
>
> I obviously have a mistake in this - I just cant seem to see it for
> looking this morning.
>
> I've tried various forms of the friend declaration but the compiler
> seems to be ignoring them all.
>
> Why wont the following compile when using namespaces
>
> TIA
>
> Adrian
>
> adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
> foo.cc:18:12: warning: unused parameter 'os'
> foo.cc:32:5: warning: unused parameter 'argc'
> foo.cc:32:5: warning: unused parameter 'argv'
>
> adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
> -Weffc++ foo.cc
> foo.cc:18:12: warning: unused parameter 'os'
> foo.cc:32:5: warning: unused parameter 'argc'
> foo.cc:32:5: warning: unused parameter 'argv'
> foo.cc: In function 'std::ostream& operator<<(std::ostream&, const
> level1::level2::foo&)':
> foo.cc:18:12: error: 'void level1::level2::foo::print(std::ostream&)
> const' is private
> foo.cc:43:16: error: within this context
>
>
>
> #include <iostream>
>
> #ifdef NAMESPACES
> namespace level1
> {
> namespace level2
> {
> #endif
> class foo
> {
> public:
> #ifdef NAMESPACES
> friend std::ostream &operator<<(std::ostream &os, const
> ::level1::level2::foo &rhs);


This declaration of 'operator<<' is in the level1::level2 namespace. If
you want it to be in the anonymous namespace, you'll have to declare it
as 'friend std::ostream& ::operator<<(...)'.

> #else
> friend std::ostream &operator<<(std::ostream &os, const foo &rhs);
> #endif
> private:
> void print(std::ostream &os) const
> {
> }
> };
> #ifdef NAMESPACES
> }}
> #endif
>
> #ifdef NAMESPACES
> std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs);
> #else
> std::ostream &operator<<(std::ostream &os, const foo &rhs);
> #endif
>
> int main(int argc, char *argv[])
> {
> return 0;
> }
>
> #ifdef NAMESPACES
> std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs)
> #else
> std::ostream &operator<<(std::ostream &os, const foo &rhs)
> #endif
> {
> rhs.print(os);
> return os;
> }



Victor Bazarov 01-13-2011 03:40 PM

Re: Compiler error with friend
 
On 1/13/2011 10:26 AM, Adrian wrote:
> Hi Guys,
>
> I obviously have a mistake in this - I just cant seem to see it for
> looking this morning.
>
> I've tried various forms of the friend declaration but the compiler
> seems to be ignoring them all.
>
> Why wont the following compile when using namespaces
>
> TIA
>
> Adrian
>
> adrianc@dluadrianc:~> g++ -Wall -ansi -pedantic -Wextra -Weffc++ foo.cc
> foo.cc:18:12: warning: unused parameter 'os'
> foo.cc:32:5: warning: unused parameter 'argc'
> foo.cc:32:5: warning: unused parameter 'argv'
>
> adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
> -Weffc++ foo.cc
> foo.cc:18:12: warning: unused parameter 'os'
> foo.cc:32:5: warning: unused parameter 'argc'
> foo.cc:32:5: warning: unused parameter 'argv'
> foo.cc: In function 'std::ostream& operator<<(std::ostream&, const
> level1::level2::foo&)':
> foo.cc:18:12: error: 'void level1::level2::foo::print(std::ostream&)
> const' is private
> foo.cc:43:16: error: within this context
>
>
>
> #include <iostream>
>
> #ifdef NAMESPACES
> namespace level1
> {
> namespace level2
> {
> #endif
> class foo
> {
> public:
> #ifdef NAMESPACES
> friend std::ostream &operator<<(std::ostream &os, const
> ::level1::level2::foo &rhs);
> #else
> friend std::ostream &operator<<(std::ostream &os, const foo &rhs);
> #endif


You're going to avoid many problems if you declare those functions where
they are supposed to reside *before* using their name in a friend
declaration. Try it. Before your present 'namespace level1' write the
function "prototype":

std::ostream &operator<<(std::ostream &os,
const level1::level2::foo &rhs);

As you can see, you will need the have 'foo' declared as well. In order
to do that, *before* the function declaration, write

namespace level1 { namespace level2 { class foo; } }

which will declare that 'foo' is a class inside those namespaces. That
should take care of it.

Namespaces can be re-opened in a translation unit (or even across them).
The forward-declaration of 'foo' will allow the compiler to create a
function declaration of the proper type. The 'friend' declaration then
will connect the class with the previously declared function. Then,
when you finally define the function, the compiler will know that you meant.

> private:
> void print(std::ostream &os) const
> {
> }
> };
> #ifdef NAMESPACES
> }}
> #endif
>
> #ifdef NAMESPACES
> std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs);
> #else
> std::ostream &operator<<(std::ostream &os, const foo &rhs);
> #endif
>
> int main(int argc, char *argv[])
> {
> return 0;
> }
>
> #ifdef NAMESPACES
> std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs)
> #else
> std::ostream &operator<<(std::ostream &os, const foo &rhs)
> #endif
> {
> rhs.print(os);
> return os;
> }


V
--
I do not respond to top-posted replies, please don't ask

Adrian 01-13-2011 03:40 PM

Re: Compiler error with friend
 
On 01/13/2011 08:34 AM, Kevin P. Fleming wrote:
> This declaration of 'operator<<' is in the level1::level2 namespace. If
> you want it to be in the anonymous namespace, you'll have to declare it
> as 'friend std::ostream& ::operator<<(...)'.

Hi Keven,

Tried that as well. Different error - but didnt work. :-(

12 #ifdef NAMESPACES
13 friend std::ostream &::operator<<(std::ostream &os, const
::level1::level2::foo &rhs);
14 #else

adrianc@dluadrianc:~> g++ -DNAMESPACES -Wall -ansi -pedantic -Wextra
-Weffc++ foo.cc
foo.cc:13:91: error: 'std::ostream& operator<<(std::ostream&, const
level1::level2::foo&)' should have been declared inside '::'
foo.cc:18:12: warning: unused parameter 'os'
foo.cc:32:5: warning: unused parameter 'argc'
foo.cc:32:5: warning: unused parameter 'argv'

Adrian 01-13-2011 03:53 PM

Re: Compiler error with friend
 
Thanks Guys, got it now with combination of forward decl and marking
operator<< as global scope. So basically a combination of Victor's and
Kevin's replies.



#include <iostream>

namespace level1 {namespace level2 { class foo; }}
std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs);

namespace level1
{
namespace level2
{
class foo
{
public:
friend std::ostream &::operator<<(std::ostream &os, const foo &rhs);
private:
void print(std::ostream &os) const
{
}
};
}}



int main(int argc, char *argv[])
{
return 0;
}

std::ostream &operator<<(std::ostream &os, const level1::level2::foo &rhs)
{
rhs.print(os);
return os;
}

Ulrich Eckhardt 01-13-2011 05:37 PM

Re: Compiler error with friend
 
Adrian wrote:
> Thanks Guys, got it now with combination of forward decl and marking
> operator<< as global scope. So basically a combination of Victor's and
> Kevin's replies.


Actually, Leigh's suggestion was the best of the three.

> namespace level1 {namespace level2 { class foo; }}
> std::ostream &operator<<(std::ostream &os, const level1::level2::foo
> &rhs);
>
> namespace level1
> {
> namespace level2
> {
> class foo
> {
> public:
> friend std::ostream &
> ::operator<<(std::ostream &os, const foo &rhs);
> private:
> void print(std::ostream &os) const
> {
> }
> };
> }}

[...]
> std::ostream &
> operator<<(std::ostream &os, const level1::level2::foo &rhs)
> {
> rhs.print(os);
> return os;
> }


Actually, I'd like to ask why you want the operator<< overload to be in
the global namespace? There is no need for this due to ADL (Argument-
Dependent Lookup aka Koenig Lookup), which basically means it will be
found even if it is in the namespace, just by the parameters given to it.

Additionally, you can declare and define the operator inline, which saves
quite a bit of typing. Since it also is very short, it doesn't hurt that
it is inline either.

Uli


James Kanze 01-13-2011 07:38 PM

Re: Compiler error with friend
 
On Jan 13, 3:44 pm, Leigh Johnston <le...@i42.co.uk> wrote:
> On 13/01/2011 15:26, Adrian wrote:


[...]
> Use friend name injection; that should solve your problem
> (there is no need to define operator<< at global scope due to
> ADL).


I'm not sure about your vocabulary here. What do you mean by
"friend name injection"? The names of a friend used to be
injected into the surrounding scope, but this was removed from
the standard. ADL does do a sort of injection, but this is
limited. (It will work in the case of operator<<. But it can
fail to work in some other special cases. ADT only kicks in
once the compiler has found a function. ADT will add to the
overload set, but it won't be used if the initial overload set
is empty.)

--
James Kanze

James Kanze 01-14-2011 09:07 AM

Re: Compiler error with friend
 
On Jan 13, 7:48 pm, Leigh Johnston <le...@i42.co.uk> wrote:
> On 13/01/2011 19:38, James Kanze wrote:
> > On Jan 13, 3:44 pm, Leigh Johnston<le...@i42.co.uk> wrote:
> >> On 13/01/2011 15:26, Adrian wrote:


> > [...]
> >> Use friend name injection; that should solve your problem
> >> (there is no need to define operator<< at global scope due to
> >> ADL).


> > I'm not sure about your vocabulary here. What do you mean by
> > "friend name injection"? The names of a friend used to be
> > injected into the surrounding scope, but this was removed from
> > the standard. ADL does do a sort of injection, but this is
> > limited. (It will work in the case of operator<<. But it can
> > fail to work in some other special cases. ADT only kicks in
> > once the compiler has found a function. ADT will add to the
> > overload set, but it won't be used if the initial overload set
> > is empty.)


> struct foo
> {
> friend void friend_name_injection(const foo& a) { std::cout <<
> a.iPrivateBits; }
> public:
> foo() : iPrivateBits(42) {}
> private:
> int iPrivateBits;
> };


> int main()
> {
> foo o;
> friend_name_injection(o);
> }


This doesn't use friend name injection, but ADL. And while this
particular example does seem to work, I had a problem recently
with something very similar, which failed to compile with g++.
(But looking at it, my case was slightly different.)

Friend name injection, as defined in the ARM and other
prestandard documents, would have resulted in
friend_name_injection being found even without ADL (which didn't
exist back then); a friend declaration always injected the name
into the surrounding scope (or back then, in pre namespace days,
file scope).

There's an issue I'm not too sure about (although I know what
compilers actually do, and I don't expect that to change). ADL
is only used for the postfix-expression of a function call. But
the meaning of () is context dependent. Given the expression
friend_name_injection(o), above, how does the compiler decide
whether the () is a function call, or part of an "Explicit type
conversion (functional notation)"? The obvious answer is that
it is a function call, because friend_name_injection is the name
of a function. The compiler cannot find friend_name_injection
(to know that it is function, and not the name of a type) until
it uses ADL, and it cannot use ADL until it knows that
friend_name_injection is not the name of a type.

I think I'll raise the issue in comp.std.c++. Given the
expression `f(a)', all of the compilers I know assume a function
call until proven otherwise, but I can't find anything in the
standard to support this.

> Are you claiming that the above code will become illegal in
> C++0x? If not then how can it be that friend name injection
> is being removed?


No, but the reason it works is ADL, and not friend name
injection.

--
James Kanze

Kevin P. Fleming 01-14-2011 02:08 PM

Re: Compiler error with friend
 
On 01/14/2011 07:20 AM, Leigh Johnston wrote:
> On 14/01/2011 13:03, Leigh Johnston wrote:
>> On 14/01/2011 12:48, Leigh Johnston wrote:
>>> On 14/01/2011 09:07, James Kanze wrote:
>>>> On Jan 13, 7:48 pm, Leigh Johnston<le...@i42.co.uk> wrote:
>>>>> On 13/01/2011 19:38, James Kanze wrote:
>>>>>> On Jan 13, 3:44 pm, Leigh Johnston<le...@i42.co.uk> wrote:
>>>>>>> On 13/01/2011 15:26, Adrian wrote:
>>>>
>>>>>> [...]
>>>>>>> Use friend name injection; that should solve your problem
>>>>>>> (there is no need to define operator<< at global scope due to
>>>>>>> ADL).
>>>>
>>>>>> I'm not sure about your vocabulary here. What do you mean by
>>>>>> "friend name injection"? The names of a friend used to be
>>>>>> injected into the surrounding scope, but this was removed from
>>>>>> the standard. ADL does do a sort of injection, but this is
>>>>>> limited. (It will work in the case of operator<<. But it can
>>>>>> fail to work in some other special cases. ADT only kicks in
>>>>>> once the compiler has found a function. ADT will add to the
>>>>>> overload set, but it won't be used if the initial overload set
>>>>>> is empty.)
>>>>
>>>>> struct foo
>>>>> {
>>>>> friend void friend_name_injection(const foo& a) { std::cout<<
>>>>> a.iPrivateBits; }
>>>>> public:
>>>>> foo() : iPrivateBits(42) {}
>>>>> private:
>>>>> int iPrivateBits;
>>>>> };
>>>>
>>>>> int main()
>>>>> {
>>>>> foo o;
>>>>> friend_name_injection(o);
>>>>> }
>>>>
>>>> This doesn't use friend name injection, but ADL. And while this
>>>> particular example does seem to work, I had a problem recently
>>>> with something very similar, which failed to compile with g++.
>>>> (But looking at it, my case was slightly different.)
>>>>
>>>> Friend name injection, as defined in the ARM and other
>>>> prestandard documents, would have resulted in
>>>> friend_name_injection being found even without ADL (which didn't
>>>> exist back then); a friend declaration always injected the name
>>>> into the surrounding scope (or back then, in pre namespace days,
>>>> file scope).
>>>>
>>>> There's an issue I'm not too sure about (although I know what
>>>> compilers actually do, and I don't expect that to change). ADL
>>>> is only used for the postfix-expression of a function call. But
>>>> the meaning of () is context dependent. Given the expression
>>>> friend_name_injection(o), above, how does the compiler decide
>>>> whether the () is a function call, or part of an "Explicit type
>>>> conversion (functional notation)"? The obvious answer is that
>>>> it is a function call, because friend_name_injection is the name
>>>> of a function. The compiler cannot find friend_name_injection
>>>> (to know that it is function, and not the name of a type) until
>>>> it uses ADL, and it cannot use ADL until it knows that
>>>> friend_name_injection is not the name of a type.
>>>>
>>>> I think I'll raise the issue in comp.std.c++. Given the
>>>> expression `f(a)', all of the compilers I know assume a function
>>>> call until proven otherwise, but I can't find anything in the
>>>> standard to support this.
>>>>
>>>>> Are you claiming that the above code will become illegal in
>>>>> C++0x? If not then how can it be that friend name injection
>>>>> is being removed?
>>>>
>>>> No, but the reason it works is ADL, and not friend name
>>>> injection.
>>>>
>>>
>>> Why can't you just admit when you are wrong? The code I gave is an
>>> example of friend name injection; from Wikipedia:
>>>
>>> "a C++ feature called "friend name injection", in which an in-class
>>> declaration of a friend function made the function name visible in the
>>> immediately surrounding namespace scope (possibly the global scope)."
>>>
>>> The fact that ADL is being used does not mean that friend name injection
>>> is not also happening. Friend name injection has not been removed.
>>>

>>
>> I apologize; you are correct of course and I am wrong as the following
>> illegal code shows:
>>
>> struct foo
>> {
>> friend void friend_name_injection() { std::cout << "friend name
>> injection"; }
>> public:
>> foo() : iPrivateBits(42) {}
>> private:
>> int iPrivateBits;
>> };
>>
>> int main()
>> {
>> friend_name_injection(); // error
>> }
>>
>> If injection was actually happening the error would not be an error.
>>

>
> Actually my correction was wrong; instead we were both initially
> correct; *injection* is happening but the function is only accessible
> via ADL:
>
> struct foo
> {
> public:
> friend void friend_name_injection() { std::cout << "friend name
> injection"; }
> public:
> foo() : iPrivateBits(42) {}
> private:
> int iPrivateBits;
> };
>
> void friend_name_injection() // error, function already has a body.
> {
> }


That seems a bit strange... if the function can only be accessed through
ADL, then there's no value in injecting its name into the enclosing
namespace, is there?

James Kanze 01-14-2011 06:39 PM

Re: Compiler error with friend
 
On Jan 14, 12:48 pm, Leigh Johnston <le...@i42.co.uk> wrote:
> On 14/01/2011 09:07, James Kanze wrote:


[...]
> > No, but the reason it works is ADL, and not friend name
> > injection.


> Why can't you just admit when you are wrong?


Because I'm not. I was actually there when freind name
injection was voted out.

> The code I gave is an
> example of friend name injection; from Wikipedia:


> "a C++ feature called "friend name injection", in which an in-class
> declaration of a friend function made the function name visible in the
> immediately surrounding namespace scope (possibly the global scope)."


So the Wikipedia is wrong. (Nothing new there.) The reference
for C++ is not the Wikipedia, but the C++ standard. The only
injection defined in the C++ is class name injection: the name
of a class is injected into that class.

> The fact that ADL is being used does not mean that friend name
> injection is not also happening. Friend name injection has
> not been removed.


It's certainly not present in the current (C++03) standard. It
wasn't present in C++98 either, although it was present in the
ARM (1989, I think).

--
James Kanze


All times are GMT. The time now is 10:31 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.