ADL 失败(或未完成?)具有附加(非推导)模板参数的函数

ADL fails (or not done?) for function with additional (non deduced) template parameter

本文关键字:参数 函数 未完成 失败 ADL      更新时间:2023-10-16
namespace N {
class C {};
template<typename X>
char const * found(X && x) {
return "found";
}
template<typename, typename X>
char const * notfound(X && x) {
return "not found";
}
}

这将定义一个具有类C和两个函数模板的命名空间Nfound有一个模板参数,可以从函数参数中推导出来。notfound有一个无法推断的附加模板参数。

给定以下测试代码(在 ideone 上):

#include <iostream>
int main() {
N::C object;
std::cout
<< found(object) << std::endl
<< notfound<bool>(object) << std::endl  // ERROR
<< notfound<bool, N::C>(object) << std::endl; // ERROR
}

我假设参数相关查找将通过参数类型N::C的最内层封闭命名空间(N)找到foundnotfound

然而:

prog.cpp: In function ‘int main()’:
prog.cpp:21:6: error: ‘notfound’ was not declared in this scope
<< notfound<bool>(object) << std::endl
^~~~~~~~
prog.cpp:21:6: note: suggested alternative:
prog.cpp:12:15: note:   ‘N::notfound’
char const * notfound(X && x) {
^~~~~~~~

(注释掉notfound<bool>(object)调用后notfound<bool, N::C>(object)相同的错误)

为什么无法通过 ADL 找到notfound


背景:我正在为一些包装类实现一个get函数,总之与std::get(std::tuple)相对相似。包装类作为实现细节,存在于某个命名空间lib::aspect::part::impl中。出于显而易见的原因,我不希望库的用户指定using lib::aspect::part::impl::get

因为函数调用具有显式指定的模板参数的函数模板需要通过普通查找找到模板的名称; 直到 ADL 无法启动。

从标准: $17.8.1/8 显式模板参数规范 [temp.arg.explicit]

(强调我的)

[ 注意:对于简单的函数名称,适用与参数相关的查找 即使函数名称在 叫。这是因为调用仍然具有 函数调用([basic.lookup.unqual])。但是当函数模板 使用显式模板参数时,调用没有 正确的语法形式,除非有一个函数模板 在呼叫点可见的名称。如果没有可见的此类名称,则 调用在语法上格式不正确且依赖于参数的查找 不适用。如果某些此类名称可见,则取决于参数 查找适用,其他函数模板可在其他 命名空间。[ 示例:

namespace A {
struct B { };
template<int X> void f(B);
}
namespace C {
template<class T> void f(T t);
}
void g(A::B b) {
f<3>(b);          // ill-formed: not a function call
A::f<3>(b);       // well-formed
C::f<3>(b);       // ill-formed; argument dependent lookup applies only to unqualified names
using C::f;
f<3>(b);          // well-formed because C​::​f is visible; then A​::​f is found by argument dependent lookup
}

— 尾声 ] — 尾注 ]

最后一句给出了一个可能的解决方法;你可以在任何地方添加函数模板的声明,以使名称对被调用可见。

template<typename>
void notfound();
int main() {
N::C object;
std::cout
<< found(object) << std::endl
<< notfound<bool>(object) << std::endl
<< notfound<bool, N::C&>(object) << std::endl; // btw the 2nd template argument should be N::C&
}