GCC编译通过但MSVC报reverse函数调用歧义,谁的问题?
GCC编译正常但MSVC报重载函数调用歧义的原因分析
问题现象
以下代码在GCC编译器中可正常编译,但在MSVC编译器中会报ambiguous call to overloaded function(重载函数调用歧义)错误。
测试代码
#include <string> template <typename Iter> void reverse(Iter begin, Iter end){ if (std::distance(begin, end) == 0) return; auto left = begin, right = std::prev(end); while (left < right) std::swap(*left++, *right--); } std::string reverseWordsInString(std::string str) { reverse(str.begin(), str.end()); // ambiguous call // reverse(str.data(), str.data() + str.size()); size_t wordLength = 0; for (size_t i = 0; i < str.size(); ++i) { if (str[i] != ' ') { ++wordLength; continue; } const size_t offset = i - wordLength; reverse(str.data() + offset, str.data() + i); wordLength = 0; } // reverse(std::prev(str.end(), wordLength), str.end()); // ambiguous reverse(str.data() + str.size() - wordLength, str.data() + str.size()); return str; }
MSVC错误输出
example.cpp <source>(16): error C2668: 'reverse': ambiguous call to overloaded function <source>(4): note: could be 'void reverse<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>>(Iter,Iter)' with [ _Elem=char, Iter=std::_String_iterator<std::_String_val<std::_Simple_types<char>>> ] C:/data/msvc/14.33.31631/include\xutility(5619): note: or 'void std::reverse<std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>>(const _BidIt,const _BidIt)' [found using argument-dependent lookup] with [ _Elem=char, _BidIt=std::_String_iterator<std::_String_val<std::_Simple_types<char>>> ] <source>(16): note: while trying to match the argument list '(std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>, std::_String_iterator<std::_String_val<std::_Simple_types<_Elem>>>) with [ _Elem=char ] Compiler returned: 2
原因分析
MSVC的行为符合C++标准,GCC的行为存在偏差,核心原因是**参数依赖查找(ADL)**规则的应用:
- 当调用
reverse(str.begin(), str.end())时,传入的迭代器是std::string的成员类型,属于std命名空间。根据ADL规则,编译器会同时在当前全局命名空间和迭代器所属的std命名空间中查找名为reverse的函数。 - 此时,自定义的全局
reverse模板和标准库的std::reverse模板都能匹配该调用(两者均接受双向迭代器作为参数),且没有哪个函数具备更高的重载优先级,因此触发重载歧义错误。 - 而调用
reverse(str.data(), ...)时,传入的是char*指针,它的关联命名空间是全局,ADL不会引入std::reverse,因此只会匹配自定义的reverse,不会产生歧义。
GCC未报错是因为其在该场景下对ADL或重载决议的处理存在宽松行为,但从C++标准的角度来看,MSVC的报错是正确的。
内容的提问来源于stack exchange,提问作者Sergey Kolesnik
相关产品推荐
相关产品推荐

