以下代码编译良好:
#include <string>
int dist(std::string& a, std::string& b) {
return 0;
}
int main() {
std::string a, b;
dist(a, b);
return 0;
}
但是当我将函数从dist重命名为distance:
#include <string>
int distance(std::string& a, std::string& b) {
return 0;
}
int main() {
std::string a, b;
distance(a, b);
return 0;
}
编译时遇到此错误(gcc 4.2.1):
/usr/include/c++/4.2.1/bits/stl_iterator_base_types.h: In instantiation of ‘std::iterator_traits<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >’:
b.cpp:9: instantiated from here
/usr/include/c++/4.2.1/bits/stl_iterator_base_types.h:129: error: no type named ‘iterator_category’ in ‘struct std::basic_string<char, std::char_traits<char>, std::allocator<char> >’
为什么我不能命名函数距离?
答案 0 :(得分:23)
原因是存在一个名为std::distance的标准算法,它由ADL(Argument Dependent Lookup)找到:尽管您的调用不符合std
命名空间,但您的参数类型{ {1}}和a
(即b
)与std::string
函数位于同一名称空间(即std::distance
),因此也会考虑std
用于重载解析。
如果你真的想要调用你的函数std::distance()
(我建议你不要这样做),你可以把它放在你的名字空间中,然后在调用它时完全限定函数名,或者将它保留在全局命名空间中并以这种方式调用它:
distance()
请注意,如果标准库的实现提供了 ::distance(a, b);
// ^^
的SFINAE友好版本,则单独ADL可能不会导致程序编译失败(详情请参阅{{} 3}} - 由this Q&A on StackOverflow提供。
对于iterator_traits
的SFINAE友好实现,您的编译器应该认识到iterator_traits
函数模板(因为它是模板)在给定类型std::distance()
的参数时无法实例化,因为它的返回类型:
std::string
在这种情况下,编译器只是为了重载解析而丢弃此模板并选择template< class InputIt >
typename std::iterator_traits<InputIt>::difference_type
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Trying to instantiate this with InputIt = std::string
// may result in a soft error during type deduction if
// your implementation is SFINAE-friendly, and in a hard
// error otherwise.
distance( InputIt first, InputIt last );
函数。
但是,如果您的标准库实现不提供SFINAE友好版本的distance()
,则替换失败可能发生在不符合SFINAE条件的上下文中,从而导致(硬)编译错误
此MooingDuck显示您的原始程序使用GCC 4.8.0进行编译,该程序附带了一个版本的libstdc ++,它实现了对SFINAE友好的iterator_traits
。