You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于C++依赖参数查找(ADL)标准条款的困惑及示例求证

理解C++ ADL中typedef/using的行为:澄清标准表述与实际代码的差异

你的困惑完全可以理解——ISO标准的措辞有时候确实比较绕,我们把那两条规则拆解清楚,再结合你的代码分析,就能明白到底是怎么回事了。

首先先把你提到的标准原文列出来:

  1. "用于指定类型的typedef名称和using声明不加入此集合";
  2. "考虑关联命名空间时,查找方式与将关联命名空间用作限定符时的查找(6.4.3.2)相同,除了:关联命名空间中的所有using-directive都被忽略……"

第一条规则:别误解"不加入此集合"的含义

这里的核心是搞清楚**"此集合"指的是什么**:它指的是ADL过程中会被纳入查找范围的关联命名空间/实体的集合,而不是说typedef/using指向的类型本身会被ADL彻底忽略。

换成人话解释:

  • 当你用N::C(一个typedef)作为参数类型时,ADL不会把typedef所在的命名空间N加到要查找的命名空间列表里;
  • 但它会顺着typedef找到背后的原始类型N2::B,然后把N2(原始类型所在的命名空间)加入ADL的查找范围——这才是ADL真正要去搜索的地方。

第二条规则:忽略关联命名空间内的using-directive,和typedef无关

这条规则是说,当ADL进入某个关联命名空间(比如你的代码里的N2)查找时,该命名空间内部的using namespace X;这类指令不会生效。举个例子,如果N2里写了using namespace std;,ADL不会因此去std里找函数,但这和typedef指向的类型没有任何关系——它只是限制了关联命名空间内部的using指令的作用,不会影响原始类型的关联命名空间被纳入查找。

结合你的代码具体分析

看你的示例代码:

#include <iostream>
using namespace std;
namespace N2 {
 struct B {};
 template <typename T>
 void func (const T&) {cout << __PRETTY_FUNCTION__ << endl;}
};
namespace N {
 typedef N2::B C;
}
void tfunc (N::C) {}
int main () {
 func(tfunc);
}

当你在main里调用func(tfunc)时,编译器的查找过程是这样的:

  1. 编译器需要找到func的定义,触发ADL机制;
  2. ADL会分析func的参数类型:这里参数是tfunc,它的类型是void(N::C)(一个接受N::C的函数类型);
  3. 对于函数类型的参数,ADL会进一步拆解其参数的类型——也就是N::C;
  4. N::C是N2::B的typedef,所以ADL会把N2(B所在的命名空间)列为要查找的关联命名空间;
  5. 在N2里找到了template <typename T> void func(const T&),这个模板可以匹配tfunc的类型,所以代码成功编译运行。

总结一下:标准的规则是不把typedef所在的命名空间纳入ADL查找范围,但完全保留了typedef指向的原始类型的关联命名空间的查找——这就是你的代码能找到N2::func的原因,和你最初的误解正好相反。

内容的提问来源于stack exchange,提问作者Baykov Nikita

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:01:40