有人可以向我解释一下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; }
}
但是......我的初始代码出了什么问题?
答案 0 :(得分:3)
n.m.的答案是正确的,虽然我需要更多的挖掘来解决它的原因,所以这里有一些链接:
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 中而不是在外部定义了运算符&lt;&lt;&lt; ,那么您的代码就可以了,如下所示:
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的另一个非常精细的答案。当我试图修复同样的问题时,它帮助了我(gcc 7给了我这个用于编译很好旧代版本的代码的警告)。
答案 1 :(得分:3)
考虑这个简单程序:
namespace xxx {
struct foo {
friend void bar();
};
}
int main() {
xxx::bar();
}
您将收到编译错误(也包含clang),因为bar
未在命名空间xxx
中声明。
现在考虑一下:
namespace xxx {}
void xxx::bar() {}
由于同样的生态原因,这也会失败,bar
未在命名空间xxx
中声明。
现在当你把两者结合起来时,没有理由说这个组合突然变得合法了。 bar
仍未在命名空间xxx
中声明。然而clang允许它。此行为不一致且令人困惑,最好将其描述为错误。
答案 2 :(得分:0)
我当时正在使用visual studio,所以我不确定它是否会为您解决问题,但我发现错误的唯一原因是您的运营商声明。 基本上它总是
const type_name variable_id &;
Ampersand总是排在最后,const排在第一位,对我来说它现在正在运行。
您应该更改您的运营商声明并注明:
friend std::ostream & operator<< (std::ostream &,const bar&);
在你的定义中更低:
std::ostream & foo::operator<< (std::ostream & o, const foo::bar &)