非限定查找中ADL优先级疑问:for_each重载调用为何歧义?
为何自定义
for_each与std::for_each调用出现歧义? 你误解了ADL(参数依赖查找)的作用——ADL不会赋予找到的函数优先选择权,它仅仅是扩展了名字查找的范围:当你调用一个未限定名字的函数时,编译器除了查找当前作用域和全局作用域,还会查找函数参数类型所在的所有命名空间。
问题分析
你的代码里存在两个候选的for_each模板:
- 你定义的全局模板:
template <typename It, typename F> void for_each(It begin, It end, F f) - 标准库的
std::for_each模板:template <typename _IIter, typename _Funct> _Funct for_each(_IIter, _IIter, _Funct)
当你在main里调用for_each时:
- 全局名字查找找到你定义的
for_each; - 因为迭代器参数
vec.begin()返回的__gnu_cxx::__normal_iterator属于std相关命名空间,ADL会查找std命名空间,从而找到std::for_each。
这两个模板都会被实例化,且实例化后的函数签名在重载决议中没有优先级差异:虽然std::for_each返回函数对象而你的版本返回void,但重载决议不考虑返回值类型;两个模板都能完美匹配传入的迭代器和lambda参数,也不存在模板特化程度的差异,因此编译器无法判定哪个是更优选择,最终报出歧义错误。
解决方法
- 明确限定调用的版本:
- 调用自己定义的全局版本:
::for_each(vec.begin(), vec.end(), [](int &x){});(用::指定全局作用域) - 调用标准库版本:
std::for_each(vec.begin(), vec.end(), [](int &x){});(显式写std::)
- 调用自己定义的全局版本:
- 避免与标准库同名的函数模板:自定义算法时尽量使用独特的名字,避免和
<algorithm>里的标准算法重名,从根源上避免这类冲突。
内容的提问来源于stack exchange,提问作者user3882729
相关产品推荐
相关产品推荐

