gpt4 book ai didi

c++ - 为什么 ADL 优先于 'std namespace' 中的函数,但等于用户定义的命名空间中的函数?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:04:20 24 4
gpt4 key购买 nike

我有两个 ADL 片段用于演示目的。这两个片段都已由 VC10、gcc 和 comeau C++ 编译器编译,结果对于所有三个都是相同的。

<1>针对用户定义命名空间的 using 指令的 ADL:

#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}

namespace M
{
void swap(N::T,N::T) {}
}

int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2);
}

编译结果:

error C2668: 'M::swap' : ambiguous call to overloaded function
could be 'void M::swap(N::T,N::T)'
or 'void N::swap(N::T,N::T)' [found using argument-dependent lookup]

这是预期的,因为 ADL 不优先于正常查找结果,而且 ADL 不是二等公民,ADL 搜索结果与正常(非 ADL)非限定查找 union 。这就是我们存在歧义的原因。

<2>ADL 反对使用 std 命名空间的指令:

#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {} //point 1
}

namespace M
{
void swap(N::T,N::T) {}
}

int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}

这个编译没问题。

结果是编译器选择 ADL 结果(它采用 std::swap 的先例),这意味着将调用“点 1”处的 N::swap()。只有在缺少“第 1 点”的情况下(比如我注释掉该行),编译才会使用后备 std::swap 代替。

请注意,这种方式已在许多地方用作覆盖 std::swap 的方式。但我的问题是,为什么 ADL 优先于“std 命名空间”(case2) 但被认为等于用户定义的命名空间函数 (case1)?

C++标准中有这么一段话吗?

============================================= ==================================阅读有用的答案后进行编辑,可能对其他人有帮助。

所以我调整了我的代码片段 1,现在歧义消失了,在进行重载解析时编译显然更喜欢 Nontemplate 函数!

#include <algorithm>
namespace N
{
struct T {};
void swap(T,T) {}
}

namespace M
{
template<class T>
void swap(N::T,N::T) {}
}

int main()
{
using M::swap;
N::T o1,o2;
swap(o1,o2); //here compiler choose N::swap()
}

我还调整了我的代码片段 2。只是为了让歧义看起来只是为了好玩!

#include <algorithm>
namespace N
{
struct T {};

template<class _Ty> inline
void swap(_Ty& _Left, _Ty& _Right)
{
_Ty _Tmp = _Move(_Left);
_Left = _Move(_Right);
_Right = _Move(_Tmp);
}
}

namespace M
{
void swap(N::T,N::T) {}
}

int main()
{
using std::swap;
N::T o1,o2;
swap(o1,o2);
}

gcc 和 comeau 都如预期的那样表示歧义:

"std::swap" matches the argument list, the choices that match are:
function template "void N::swap(_Ty &, _Ty &)"
function template "void std::swap(_Tp &, _Tp &)"

BTW VC10 像往常一样愚蠢让这个通过 ok 除非我删除'using std::swap'。

还有一点要写:C++ 重载可能很棘手(在 C++ 标准中有 30 多页),但是在附录 B 中有一个非常可读的 10 页...

感谢所有好的输入,现在很清楚了。

最佳答案

一个函数调用发生在几个阶段:

  1. 名称查找 -> 将候选函数放入所谓的重载集
    • 如果您有不合格的名称查找,这就是 ADL 发生的部分
  2. 模板参数推导 -> 对于重载集中的每个模板
  3. 重载分辨率 -> 选择最佳匹配

您混淆了第 1 部分和第 3 部分。名称查找实际上会将 swap 都放在一起。重载集 ( {N::swap, std::swap} ) 中的函数,但第 3 部分将决定最后调用哪一个。

现在,自 std::swap是一个模板,标准说非模板函数在进行重载解析时比模板函数更专业,你的<2>电话 N::swap :

§13.3.3 [over.match.best] p1

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if [...]

  • F1 is a non-template function and F2 is a function template specialization [...]

† 我推荐this excellent series的前三个视频关于这个问题。

关于c++ - 为什么 ADL 优先于 'std namespace' 中的函数,但等于用户定义的命名空间中的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12748212/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com