C++ `使用命名空间指令使全球范围操作员消失了吗?
由于我不明白的原因,以下C ++代码未能在VS 2022上编译(方言设置为C ++ 20):
#include <compare>
namespace N1
{}
namespace N1::N2
{
class A {};
A operator-(A&);
}
std::strong_ordering operator-(std::strong_ordering o);
namespace N1
{
using namespace N2; // (1) !!!
std::strong_ordering foo();
inline std::strong_ordering bar()
{
return -foo(); // (2) !!!
}
}
在(2),编译器文件投诉:错误c2678:biarmin' - ':no发现操作员采用了“ std :: strong_ordering”类型的左手操作数(或没有可接受的转换)
。
当使用命名空间 在(1)上删除指令时,编译器愉快地找到了运算符 -
在全球范围上定义的std :: stront :: strong_ordering
类型。
这引起了一系列问题:
- 该vs 2022行为(a)一个错误,(b)允许甚至(c)根据语言标准进行强制性?
- 如果是(b)或(c),如何?标准中的哪些特定句子允许/要求编译器到 在全局范围上找到
ocerator-
? - 您将如何建议解决这个问题,以假设使用命名空间指令的
是否可以留下来?
For reasons I do not understand, the following C++ code fails to compile on VS 2022 (dialect set to C++20):
#include <compare>
namespace N1
{}
namespace N1::N2
{
class A {};
A operator-(A&);
}
std::strong_ordering operator-(std::strong_ordering o);
namespace N1
{
using namespace N2; // (1) !!!
std::strong_ordering foo();
inline std::strong_ordering bar()
{
return -foo(); // (2) !!!
}
}
At (2), the compiler files a complaint: error C2678: binary '-': no operator found which takes a left-hand operand of type 'std::strong_ordering' (or there is no acceptable conversion)
.
When the using namespace
directive at (1) is removed, the compiler happily finds the operator-
defined at global scope for the std::strong_ordering
type.
This gives rise to a set of questions:
- Is this VS 2022 behavior (a) a bug, (b) allowed or even (c) mandatory according to the language standard?
- In case of (b) or (c), how? Which specific sentences in the standard allow/mandate the compiler to not find the
operator-
at global scope? - How would you suggest to work around the issue, presuming that the
using namespace
directive is there to stay?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的编译器是正确的,我希望其他编译器同意。
有关A 使用指导的行为,请参见C ++ 20 [namespace.udir]/2:
换句话说,如果
n1
包含使用名称空间N2;
,则仅出于未合格的名称查找的目的,则n2
中的名称将显示为它们处于n1
和n2
的最低祖先名称空间。由于n2
在n1
内N2
在执行不合格的名称查找时出现N1
。这意味着
运算符的无限制查找 -
将找到n2 ::操作员 -
,并且不会进入全局名称空间以继续搜索其他声明。请参阅[basic.lookup.unqual]/1:要解决这个问题,有两种策略。一种是将
运算符 -
放置在声明该类型的名称空间中的类型,以便通过参数依赖性查找找到。但是,您不允许将操作员的过载添加到std
名称空间。另一种策略是重新运行操作员 -
您要使用使用declaration :这有效地带来了您想要的
operator-
“一个级别”更深的”,将其与其他运算符 -
相同的水平,这要归功于使用指导性的,因此,无限制的名称查找将同时找到,并且编译器将执行执行超负荷分辨率。Your compiler is correct, and I would expect other compilers to agree.
For the behaviour of a using-directive, see C++20 [namespace.udir]/2:
In other words, if
N1
containsusing namespace N2;
, then only for the purposes of unqualified name lookup, names inN2
will appear as if they are in the lowest common ancestor namespace ofN1
andN2
. SinceN2
is insideN1
, the lowest common ancestor namespace is justN1
, and that means theoperator-
inN2
appears insideN1
when unqualified name lookup is performed.This means that unqualified lookup for
operator-
will findN2::operator-
, and it won't proceed to the global namespace to continue searching for additional declarations. See [basic.lookup.unqual]/1:To work around the issue, there are two strategies. One is to place the
operator-
for your type in the namespace where that type is declared, so it can be found via argument-dependent lookup. However, you are not allowed to add operator overloads to thestd
namespace. The other strategy is to redeclare theoperator-
you want using a using-declaration:This effectively brings the
operator-
that you want "one level deeper", putting it at the same level as the otheroperator-
that appears thanks to the using-directive, so unqualified name lookup will find both, and the compiler will perform overload resolution.运算符 - 来解决问题。
我现在通过让
运算符 -
在std ::
,即:我不确定搞乱是否很好的练习中,通过使用
std ::
namespace;欢迎评论。I'm now working around the issue by having the
operator-
live instd::
, i.e.:However, I'm not really sure whether it is good practice to mess with the
std::
namespace; comments welcome.