基于模板参数推导利用的 STL 算法名称可解析或未定义
STL algorithm name resolvable or undefined based on template argument deduction utilization
鉴于此代码:
#include <algorithm>
#include <vector>
using std::vector;
int main()
{
vector<int> intVec(100, 1);
// no problem
random_shuffle(intVec.begin(), intVec.end());
// no problem
std::random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
// random_shuffle undefined!
random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
}
我意识到这段代码中的名称管理很糟糕。然而,一个不太小的代码库激发了我的问题。 random_shuffle 是可解析的,没有 std 资格。如果合格且明确模板化,则不再有问题。但是,如果没有 std 限定和显式模板参数(至少隐式正确),random_shuffle 突然未定义。为什么?
Visual Studio 2017(我知道...如果这是MS恶作剧,就这么说)
函数调用表达式的非限定名称查找也可能会考虑关联的命名空间,以便找到引用的函数。此功能称为 Argument-dependent lookup。正在搜索的关联命名空间集包括函数调用参数本身类型的命名空间,以及函数调用参数的 class 模板类型的模板参数的命名空间。换句话说,对于函数调用:
foo(A::B<C::D>{});
关联的命名空间集包括 namespace A
和 namespace C
,检查两者以查找函数声明 foo
。
第一种情况:
random_shuffle(intVec.begin(), intVec.end());
std::random_shuffle
是通过 ADL 找到的,它被触发只是因为在 VC++ 标准库实现中 std::vector<int>::iterator
是 [=19] 中定义的 class 类型=] 命名空间 (std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
),因此 std
是执行名称查找的关联命名空间。但是,这不能保证有效,因为向量迭代器也可以是指针,或者位于 namespace std
.
之外
第二种情况:
std::random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
编译器执行限定名称查找。
第三种情况:
random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
以下要点适用:
8 (...) when a function template with explicit template arguments is used, the call does not have
the correct syntactic form unless there is a function template with that name visible at the point of the call.
If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply.
换句话说,f(a)
可以触发 ADL,但是 f<B>(a)
- 显式向函数调用提供模板参数,这正是你的情况 - 不能。
这个项目符号似乎只在 C++20 之前有效。
鉴于此代码:
#include <algorithm>
#include <vector>
using std::vector;
int main()
{
vector<int> intVec(100, 1);
// no problem
random_shuffle(intVec.begin(), intVec.end());
// no problem
std::random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
// random_shuffle undefined!
random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
}
我意识到这段代码中的名称管理很糟糕。然而,一个不太小的代码库激发了我的问题。 random_shuffle 是可解析的,没有 std 资格。如果合格且明确模板化,则不再有问题。但是,如果没有 std 限定和显式模板参数(至少隐式正确),random_shuffle 突然未定义。为什么?
Visual Studio 2017(我知道...如果这是MS恶作剧,就这么说)
函数调用表达式的非限定名称查找也可能会考虑关联的命名空间,以便找到引用的函数。此功能称为 Argument-dependent lookup。正在搜索的关联命名空间集包括函数调用参数本身类型的命名空间,以及函数调用参数的 class 模板类型的模板参数的命名空间。换句话说,对于函数调用:
foo(A::B<C::D>{});
关联的命名空间集包括 namespace A
和 namespace C
,检查两者以查找函数声明 foo
。
第一种情况:
random_shuffle(intVec.begin(), intVec.end());
std::random_shuffle
是通过 ADL 找到的,它被触发只是因为在 VC++ 标准库实现中 std::vector<int>::iterator
是 [=19] 中定义的 class 类型=] 命名空间 (std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>
),因此 std
是执行名称查找的关联命名空间。但是,这不能保证有效,因为向量迭代器也可以是指针,或者位于 namespace std
.
第二种情况:
std::random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
编译器执行限定名称查找。
第三种情况:
random_shuffle<vector<int>::iterator>(intVec.begin(), intVec.end());
以下要点适用:
8 (...) when a function template with explicit template arguments is used, the call does not have the correct syntactic form unless there is a function template with that name visible at the point of the call. If no such name is visible, the call is not syntactically well-formed and argument-dependent lookup does not apply.
换句话说,f(a)
可以触发 ADL,但是 f<B>(a)
- 显式向函数调用提供模板参数,这正是你的情况 - 不能。
这个项目符号似乎只在 C++20 之前有效。