ADL 失败(或未完成?)具有附加(非推导)模板参数的函数
ADL fails (or not done?) for function with additional (non deduced) template parameter
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
和两个函数模板的命名空间N
。found
有一个模板参数,可以从函数参数中推导出来。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
)找到found
和notfound
。
然而:
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&
}
住
- 将可变参数函数的参数封装在类实例中
- QML 使用带有参数C++函数
- 使用可变参数函数作为模板参数
- 如何在C++中伪造虚拟可变参数函数模板?
- 为什么可变参数函数不适用于模板
- C++ std::functional 中的可变参数函数模板
- 可变参数函数指针的定义对于VxWorks spyLib来说不清楚
- 使用可变参数函数覆盖具有不同函数签名的虚函数
- 考虑引用和常量的可变参数函数包装器
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 在可变参数函数中转发特定范围的参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 使用带有一个参数函数的递归找到数字的平方
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 多个可变参数函数的单个模板参数包?
- 参数数据类型未知的可变参数函数
- 可变参数函数参数包扩展
- 使用模板可变参数函数将多个参数传递给另一个函数
- 对可变参数函数的递归调用的链接器错误
- 通过像printf这样的可变参数函数传递一个带有常量字符*转换函数的类