2013-06-03 42 views
14

下面的代码编译好:不能使用函数名距离

#include <string> 

int dist(std::string& a, std::string& b) { 
    return 0; 
} 

int main() { 
    std::string a, b; 
    dist(a, b); 
    return 0; 
} 

但是,当我的功能重新命名DIST到距离:

#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

我马上就知道问题出在哪里。如果只有我在3小时前在这里。大声笑 – 0x499602D2

回答

23

的原因是,一个名为std::distance标准算法存在的,这是由ADL(参数依赖查找)发现:虽然您的通话是没有资格与std命名空间,你的论点ab(即std::string)生活型在与std::distance函数(即std)相同的名称空间中,因此std::distance()也被视为重载解析。

如果你真的想打电话给你的函数distance()(我建议你不要),你可以把它放在你的名字空间中,然后在你调用它时完全限定函数名,或者把它放在全局命名空间,并调用它是这样的:

::distance(a, b); 
// ^^ 

通知,但是,ADL单独可能导致程序无法编译,如果你的标准库的实现提供的iterator_traits一个SFINAE的版本(更详情请见this Q&A on StackOverflow - 礼貌MooingDuck)。

随着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); 

在这种情况下,编译器会为了重载解析而简单地放弃此模板并选择distance()函数。但是,如果您对标准库的实现不提供适用于SFINAE的iterator_traits版本,则在不符合SFINAE的上下文中可能会发生替换失败,从而导致(硬)编译错误。

这个live example显示你的原始程序与GCC 4.8.0编译,它附带一个版本的libstdC++,实现SFINAE友好的iterator_traits

+3

不应该这只是一个问题,如果使用名称空间标准;出现虽然? –

+0

所以我只需要选择另一个名字?有没有办法来命名我的功能距离? – egoard

+0

@egoard:我建议你选择另一个名字,是的。但是,如果你真的想保留'distance()',那么你可以通过明确地告诉编译器,你需要位于全局命名空间中的函数'distance()'来限定调用(正如我上次编辑中的建议) –