2013-06-03 18 views
14

Der folgende Code kompiliert fein verwenden:Kann nicht Funktionsname Entfernung

#include <string> 

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

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

Aber wenn ich die Funktion von dist Abstand umbenennen:

#include <string> 

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

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

ich diese Fehlermeldung erhalten, wenn (gcc 4.2 kompilieren .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> >’ 

Warum kann ich den Funktionsabstand nicht nennen?

+0

Ich wusste sofort, was das Problem war. Wenn ich nur drei Stunden früher hier wäre. Lol – 0x499602D2

Antwort

23

Der Grund dafür ist, dass ein Standard-Algorithmus genannt std::distance existiert, die von ADL (Argumente abhängige Lookup) gefunden wird: Obwohl Ihr Anruf mit dem std Namespace nicht qualifiziert ist, die Art Ihrer Argumente a und b (dh std::string) Leben im selben Namespace wie die std::distance-Funktion (dh std), und daher wird auch std::distance() für die Überlastungsauflösung berücksichtigt.

Wenn Sie wirklich Ihre Funktion distance() aufrufen möchten (ich würde vorschlagen, Sie nicht), können Sie entweder in einem Namespace von Ihnen eingeben, und dann den Funktionsnamen vollständig qualifizieren, wenn Sie es aufrufen, oder lassen Sie es der globale Namespace und rufen sie es auf diese Weise:

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

Beachten sie jedoch, dass ADL allein könnte nicht Ursache Ihr Programm kompiliert wird scheitern, wenn Ihre Implementierung der Standardbibliothek eine SFINAE freundliche Version iterator_traits bietet (mehr Details in this Q&A on StackOverflow - mit freundlicher Genehmigung von MooingDuck).

Mit einer SFINAE freundlichen Umsetzung von iterator_traits, Compiler, dass die std::distance() Funktion Vorlage erkennen soll (weil es eine Vorlage) nicht instanziiert, wenn Argumente von std::string Art gegeben werden kann, aufgrund seines Rückgabetypen:

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

In diesem Fall würde der Compiler diese Vorlage einfach für die Überladungsauflösung verwerfen und Ihre distance() Funktion auswählen.

Wenn jedoch Ihre Implementierung der Standardbibliothek keine SFINAE-freundliche Version von iterator_traits bereitstellt, kann in einem Kontext, der nicht für SFINAE geeignet ist, ein Substitutionsfehler auftreten, was zu einem (harten) Kompilierungsfehler führt.

Diese live example zeigt Ihr ursprüngliches Programm kompilierend mit GCC 4.8.0, das mit einer Version von libstdC++ geliefert wird, die eine SFINAE-freundliche iterator_traits implementiert.

+3

Sollte das nicht nur ein Problem sein, wenn 'using namespace std;' trotzdem erscheint? –

+0

Also muss ich nur einen anderen Namen wählen? Es gibt keine Möglichkeit, meinen Funktionsabstand zu nennen? – egoard

+0

@egoard: Ich würde vorschlagen, dass Sie einen anderen Namen wählen, ja. Aber wenn Sie 'distance()' wirklich behalten wollen, dann können Sie den Aufruf qualifizieren, indem Sie dem Compiler explizit mitteilen, dass Sie die Funktion 'distance()' im globalen Namensraum haben wollen (wie in der letzten Bearbeitung meiner Antwort vorgeschlagen)) –

Verwandte Themen