警告定义在命名空间内声明的友元运算符
warning defining friend operator declared inside a namespace
有人可以向我解释来自 g++ 的警告吗?
给定以下代码
#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;
}
我得到(来自 g++ (6.3.0) 但不是来自 clang++ (3.8.1) 而不是(感谢 Robert.M)来自 Visual Studio (2017 社区))这个警告
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 &); };
^~~~~~~~
我知道我可以定义运算符如下
namespace foo
{
std::ostream & operator<< (std::ostream & o, bar const &)
{ return o; }
}
但是...我的初始代码有什么问题?
我使用的是 visual studio,所以我不确定它是否能为您解决问题,但我发现的唯一错误是您的运营商声明。
基本上总是
const type_name variable_id &;
& 符号总是在最后,const 在前,对我来说现在是 运行。
您应该更改您的运算符声明并更改为:
friend std::ostream & operator<< (std::ostream &,const bar&);
你的定义更低:
std::ostream & foo::operator<< (std::ostream & o, const foo::bar &)
的答案是正确的,虽然我需要更多的挖掘才能弄明白为什么,所以这里有一些我点击的链接:
CppCoreGuidelines 解释说 "Nonmember operators should be either friends or defined in the same namespace as their operands"。
下面对why the same namespace.
做更详细的解释
也许这个 this message from the GCC mailing list 提供了更多的见解:看起来 GCC 的人在 2016 年的某个时候决定更严格地处理这个问题。
这里的关键是命名空间。如果它在命名空间 foo 而不是外部定义了 operator<< ,那么您的代码就可以了,就像这样:
namespace foo
{
struct bar
{
friend std::ostream & operator<< (std::ostream &, bar const &);
};
// Implementation
std::ostream & operator<< (std::ostream & o, foo::bar const &)
{ return o; }
}
请注意,如果将实现直接与朋友定义放在一起,这会变得更简单,如 this SO answer to a similar question 所示。
这是对 very similar question 的另一个非常详尽的 SO 回答。当我试图解决同样的问题时,它帮助了我(gcc 7 向我发出警告,警告我可以用更旧的版本编译得很好的代码)。
考虑这个简单的程序:
namespace xxx {
struct foo {
friend void bar();
};
}
int main() {
xxx::bar();
}
你会得到一个编译错误(也有 clang),因为 bar
没有在命名空间 xxx
.
中声明
现在考虑一下:
namespace xxx {}
void xxx::bar() {}
出于同样的原因,这也会失败,bar
未在命名空间 xxx
中声明。
现在,当您将两者结合起来时,没有理由认为这种结合会突然变得合法。 bar
仍未在命名空间 xxx
中声明。然而 clang 允许它。此行为不一致且令人困惑,最好将其描述为错误。
嗯,我遇到了同样的问题。但是我找到了修复它的方法:在命名空间范围内添加另一个函数声明。
就像这样:
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;
}
有人可以向我解释来自 g++ 的警告吗?
给定以下代码
#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;
}
我得到(来自 g++ (6.3.0) 但不是来自 clang++ (3.8.1) 而不是(感谢 Robert.M)来自 Visual Studio (2017 社区))这个警告
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 &); };
^~~~~~~~
我知道我可以定义运算符如下
namespace foo
{
std::ostream & operator<< (std::ostream & o, bar const &)
{ return o; }
}
但是...我的初始代码有什么问题?
我使用的是 visual studio,所以我不确定它是否能为您解决问题,但我发现的唯一错误是您的运营商声明。 基本上总是
const type_name variable_id &;
& 符号总是在最后,const 在前,对我来说现在是 运行。
您应该更改您的运算符声明并更改为:
friend std::ostream & operator<< (std::ostream &,const bar&);
你的定义更低:
std::ostream & foo::operator<< (std::ostream & o, const foo::bar &)
CppCoreGuidelines 解释说 "Nonmember operators should be either friends or defined in the same namespace as their operands"。
下面对why the same namespace.
做更详细的解释
也许这个 this message from the GCC mailing list 提供了更多的见解:看起来 GCC 的人在 2016 年的某个时候决定更严格地处理这个问题。
这里的关键是命名空间。如果它在命名空间 foo 而不是外部定义了 operator<< ,那么您的代码就可以了,就像这样:
namespace foo
{
struct bar
{
friend std::ostream & operator<< (std::ostream &, bar const &);
};
// Implementation
std::ostream & operator<< (std::ostream & o, foo::bar const &)
{ return o; }
}
请注意,如果将实现直接与朋友定义放在一起,这会变得更简单,如 this SO answer to a similar question 所示。
这是对 very similar question 的另一个非常详尽的 SO 回答。当我试图解决同样的问题时,它帮助了我(gcc 7 向我发出警告,警告我可以用更旧的版本编译得很好的代码)。
考虑这个简单的程序:
namespace xxx {
struct foo {
friend void bar();
};
}
int main() {
xxx::bar();
}
你会得到一个编译错误(也有 clang),因为 bar
没有在命名空间 xxx
.
现在考虑一下:
namespace xxx {}
void xxx::bar() {}
出于同样的原因,这也会失败,bar
未在命名空间 xxx
中声明。
现在,当您将两者结合起来时,没有理由认为这种结合会突然变得合法。 bar
仍未在命名空间 xxx
中声明。然而 clang 允许它。此行为不一致且令人困惑,最好将其描述为错误。
嗯,我遇到了同样的问题。但是我找到了修复它的方法:在命名空间范围内添加另一个函数声明。
就像这样:
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;
}