未命名的命名空间和 iostream 导致“!= 非法操作”
#include <functional>
#include <iostream>
struct A {
friend bool operator==( const A & a, const A & b ){
return true;
}
};
namespace {
bool operator!=( const A &a, const A & b){
return !(a==b);
}
}
int main(int argc, char **argv) {
std::not_equal_to<A> neq;
A a;
bool test = neq(a, a);
return test ? 0 : 1;
}
在 CC
(SunOs 编译器)上失败:
Error: The operation "const A != const A" is illegal.
"tempcc.cpp", line 16: Where: While instantiating "std::not_equal_to<A>::operator()(const A&, const A&) const".
"tempcc.cpp", line 16: Where: Instantiated from non-template code.
在 g++
上失败:
/usr/local/include/c++/3.3.2/bits/stl_function.h: In member function `bool std::not_equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]':
tempcc.cpp:16: instantiated from here
/usr/local/include/c++/3.3.2/bits/stl_function.h:183: error: no match for 'operator!=' in '__x != __y'
但是,如果我删除行 #include
它会编译并且运行得很好。有谁敢来解释一下吗?
#include <functional>
#include <iostream>
struct A {
friend bool operator==( const A & a, const A & b ){
return true;
}
};
namespace {
bool operator!=( const A &a, const A & b){
return !(a==b);
}
}
int main(int argc, char **argv) {
std::not_equal_to<A> neq;
A a;
bool test = neq(a, a);
return test ? 0 : 1;
}
This fails on CC
(SunOs Compiler) with:
Error: The operation "const A != const A" is illegal.
"tempcc.cpp", line 16: Where: While instantiating "std::not_equal_to<A>::operator()(const A&, const A&) const".
"tempcc.cpp", line 16: Where: Instantiated from non-template code.
And on g++
with:
/usr/local/include/c++/3.3.2/bits/stl_function.h: In member function `bool std::not_equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]':
tempcc.cpp:16: instantiated from here
/usr/local/include/c++/3.3.2/bits/stl_function.h:183: error: no match for 'operator!=' in '__x != __y'
However if I remove the line #include <iostream>
it compiles and runs just fine. Anyone dare to explain this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据 Comeau 的说法,这两种方式都不合法 - 事实上,当您不
#include
时编译器会构建它,这可能是实际的错误,而不是相反(或者至少在解释上存在分歧):这是有道理的,这不会构建 - 将
operator!=
放置在未命名的命名空间中仍然会将其放置在与::
不同的命名空间中,我不完全确定为什么g++ 在没有包含 iostream 的情况下构建它 - 如果您查看 g++ 的预处理器输出,它没有做任何重新排序代码的事情或任何此类废话,当然还有 iostream没有为A
定义operator!=
。我手边没有 C++ 标准的副本,但是 此链接 来自 IBM 至少验证了未命名命名空间不混合的说法与全局操作符一样好,解释了为什么找不到您定义的
operator!=
。您还可能在匿名命名空间歧义中找到一些有用的信息。
According to Comeau, this isn't legal either way - the fact that the compiler builds it when you don't
#include <iostream>
may be the actual bug, not the other way around (or at least a disagreement in interpretation):It makes sense that this doesn't build - placing
operator!=
in an unnamed namespace still puts it in a different namespace than::
, and I'm not entirely sure why g++ builds it without theiostream
include - if you look at the preprocessor output from g++ it hasn't done anything hinky to reorder code or any such nonsense, and of courseiostream
doesn't defineoperator!=
forA
.I do not have my copy of the C++ standard handy, but this link from IBM at least validates the claim that unnamed namespaces don't mix that well with the global one, explaining why you can't find the
operator!=
you've defined.You also might find some helpful information in Anonymous Namespace Ambiguity.
问题在于
还从tuple
和utility
中提取了几个干扰查找的模板。如果您要删除它,例如仅在 GCC 中包含
,那么就没有问题,尽管这当然不是真正的解决方案。我想如果您需要谓词,您无法绕过实现您自己的operator!=()
或添加std::not_equal_to
的显式专业化。但是,如果您不需要使用
not_equal_to
谓词,则可以通过删除所有自定义代码并添加以下内容来完全规避该问题:The problem is that
<functional>
also pulls in several templates from fromtuple
andutility
that interfere with the lookup.If you were to remove this, e.g. by only including
<bits/stl_function.h>
in GCC, then there is no problem, although is is of course not a real solution. I suppose you cannot get around either implementing your ownoperator!=()
or adding an explicit specialization forstd::not_equal_to
if you require the predicate.However, if you don't need to use the
not_equal_to
predicate, you can circumvent the problem entirely by removing all your custom code and adding the following: