2013-06-03 4 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; 
} 

Но когда я переименовать функцию от дист расстоянию:

#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 часа назад. Lol – 0x499602D2

ответ

23

Причина заключается в том, что стандартный алгоритм называется std::distance существует, которое находится ADL (Довод Dependent Lookup): хотя ваш звонок не квалифицирован с std именами, типа ваших аргументов a и b (т.е. std::string) жизни в том же пространстве имен, что и функция std::distance (то есть std), и поэтому std::distance() также рассматривается для разрешения перегрузки.

Если вы действительно хотите позвонить своей функции distance() (я бы предложил вам не делать этого), вы можете либо поместить ее в свое пространство имен, а затем полностью квалифицировать имя функции, когда вы ее вызываете, или оставить ее в глобальное пространство имен и вызывать его таким образом:

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

Обратите внимание, однако, что ADL в одиночку может не причина, чтобы ваша программа не в состоянии компиляции, если ваша реализация стандартной библиотеки обеспечивает SFINAE-дружественную версию iterator_traits (более подробнее в 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

Не должно ли это быть проблемой только при использовании 'namespace std?'? –

+0

Так что мне просто нужно выбрать другое имя? Невозможно назвать расстояние до моей функции? – egoard

+0

@egoard: Я бы предложил вам выбрать другое имя, да. Но если вы действительно хотите сохранить 'distance()', то вы можете квалифицировать вызов, явно сообщая компилятору, что вы хотите, чтобы функция 'distance()', которая живет в глобальном пространстве имен (как было предложено в последнем редактировании для моего ответа) –

Смежные вопросы