Wak*_*zil 5 c++ templates language-lawyer argument-dependent-lookup c++11
该标准的引用表示赞赏.
#include <iostream>
namespace X {
class A {};
}
template <typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
return max(max(a, b), c);
}
inline X::A const& max(X::A const& a, X::A const& b)
{
std::cout << "non-template" << '\n';
return a;
}
int main()
{
X::A a, b, c;
max(a, b, c);
}
namespace X {
template <typename T>
inline T const& max(T const& a, T const& b)
{
std::cout << "template" << '\n';
return a;
}
}
Run Code Online (Sandbox Code Playgroud)
示例中的调用max()需要一个从属名称,因为它的参数取决于模板参数T。标准中定义了此类从属名称的两阶段名称查找,如下所示:
14.6.4.2 候选函数 [temp.dep.candidate]
\n\n\n\n\n1 对于 post\xef\xac\x81x 表达式是从属名称的函数调用,\n 使用通常的查找规则(3.4.1,\n 3.4.2)找到候选函数,除了:
\n\n\xe2\x80\x94 对于使用 unquali\xef\xac\x81ed 名称查找 (3.4.1) 的查找部分,仅找到来自模板 de\xef\xac\x81nition\n 上下文的函数声明。
\n\n\xe2\x80\x94 对于使用关联命名空间 (3.4.2) 的查找部分,仅在模板 de\xef\xac\x81nition 上下文或模板实例化上下文中找到\n 函数声明。
\n
不合格的查找定义为
\n\n3.4.1 Unquali\xef\xac\x81ed 名称查找 [basic.lookup.unqual]
\n\n\n\n\n1 在 3.4.1 列出的所有情况下,将按照每个相应类别中列出的顺序在范围中搜索声明; 一旦找到名称的声明,名称查找就会结束。如果未找到\n 声明,则程序格式错误。
\n
和参数相关的查找(ADL)为
\n\n3.4.2 参数相关名称查找 [basic.lookup.argdep]
\n\n\n\n\n1 当函数调用 (5.2.2) 中的后缀表达式是\n unqualified-id时,可能会搜索在通常的\n 非限定查找 (3.4.1) 期间未考虑的其他命名空间,并且在这些命名空间中,\n可能会发现命名空间范围的友元函数或函数模板声明\n (11.3) 不可见。对搜索的这些修改取决于参数的类型(对于模板模板参数,则取决于模板参数的命名空间)。
\n
在您的示例中,非限定查找和 ADL在定义点都没有找到任何重载,因为编译器尚未看到任何双参数max()。ADL 也适用于实例化点,此时,编译器已经看到了template max(T, T)唯一可以调用的两个参数。(不同之处在于模板实例化发生在整个翻译单元被解析之后)。
您应该通过将非模板max(X::A, X::A)重载放入其中namespace X并将template max(T, T)其移出来修复代码。
#include <iostream>\n\n// generic code\n\ntemplate <typename T>\ninline T const& max(T const& a, T const& b)\n{\n std::cout << "template" << \'\\n\';\n return a;\n}\n\ntemplate <typename T>\ninline T const& max(T const& a, T const& b, T const& c)\n{\n using ::max; // fallback if no user-defined max\n return max(max(a, b), c);\n}\n\n// X specific code\n\nnamespace X {\n\nclass A {};\n\ninline X::A const& max(X::A const& a, X::A const& b)\n{\n std::cout << "non-template" << \'\\n\';\n return a;\n}\n\n} // namespace X\n\nint main()\n{\n X::A a, b, c;\n max(a, b, c);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n打印“非模板”两次的实时示例。
\n