简体   繁体   中英

warning defining friend operator declared inside a namespace

Someone can explain me a warning from g++ ?

Given the following code

#include <iostream>

namespace foo
 {
   struct bar
    { friend std::ostream & operator<< (std::ostream &, bar const &); };
 }

std::ostream & foo::operator<< (std::ostream & o, foo::bar const &)
 { return o; }

int main ()
 {
   foo::bar  fb;

   std::cout << fb;
 }

I get (from g++ (6.3.0) but not from clang++ (3.8.1) and not (thanks Robert.M) from Visual Studio (2017 community)) this warning

tmp_002-11,14,gcc,clang.cpp:10:16: warning: ‘std::ostream& foo::operator<<(std::ostream&, const foo::bar&)’ has not been declared within foo
 std::ostream & foo::operator<< (std::ostream & o, foo::bar const &)
                ^~~
tmp_002-11,14,gcc,clang.cpp:7:29: note: only here as a friend
     { friend std::ostream & operator<< (std::ostream &, bar const &); };
                             ^~~~~~~~

I know that I can define the operator as follows

namespace foo
 {
   std::ostream & operator<< (std::ostream & o, bar const &)
    { return o; }
 }

but... what's wrong with my initial code ?

The answer of nm is right, although I needed a bit more digging to get it why, so here are some links that I followed:

The CppCoreGuidelines explain that "Nonmember operators should be either friends or defined in the same namespace as their operands" . Here's a more detailed explanation of why the same namespace .
Maybe this this message from the GCC mailing list provides even more insight: it looks as if the GCC people decided to handle this issue more strictly some time im 2016.

The key here is the namespace. Your code would be OK if it defined the operator<< within the namespace foo instead of outside, like this:

namespace foo
{
    struct bar
    { 
        friend std::ostream & operator<< (std::ostream &, bar const &);
    };

    // Implementation
    std::ostream & operator<< (std::ostream & o, foo::bar const &)
    { return o; }
}

Note that this gets simpler, if you put the implementation directly with the friend definition, as shown in this SO answer to a similar question .

Here is another, quite elaborate SO answer to a very similar question . It helped me when I tried to fix the same problem (gcc 7 gave me this waring for code that compiled fine with much older versions).

Consider this simpme program:

namespace xxx { 
    struct foo {
       friend void bar();
    };
}

int main() {
    xxx::bar();
}

You will get a compilation error (with clang too) because bar is not declared in namespace xxx .

Now consider this:

namespace xxx {}
void xxx::bar() {}

This will also fail for the same ecact reason, bar is not declared in namespace xxx .

Now when you combine the two, there's no reason why the combination should suddenly become legal. bar is still not declared in namespace xxx . Yet clang permits it. This behaviour is inconsistent and confusing, and is best described as a bug.

I was using visual studio so I am not sure if it will solve a problem for you but the only thing I found wrong was a declaration of your operator. Basicly it is always

        const type_name variable_id &;

Ampersand always comes last and const comes first, for me it is running now.

You should change your operator declaration and to:

        friend std::ostream & operator<< (std::ostream &,const bar&);

And lower in your definition:

std::ostream & foo::operator<< (std::ostream & o,  const foo::bar &)

Well, I met the same problem. However I found a way to fix it: add another declaration of the function, within the namespace scope.

Just like this:

namespace foo {
    class A {
    public:
        friend std::ifstream &operator >> (std::ifstream &in, A &a);
    };

    std::ifstream &operator >> (std::ifstream &in, A &a);
}

std::ifstream &foo::operator >> (std::ifstream &in, A &a) {
    [...]
    return in;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM