2016-04-20 12 views
2

Ich bin verwirrt, warum der folgende Code in einigen Fällen kompiliert, aber nicht andere.Warum kann ich diese C++ - Standardbibliotheksfunktion ohne std :: qualifier aufrufen?

#include <iostream> 
#include <vector> 
#include <algorithm> 

int main(){ 
    std::vector<int> v(3); 
    int a[] = {3, 6, 2}; 
    std::copy(a, a+3, v.begin()); 
#define CASE 2 
#if CASE == 0 
    std::cout << *max_element(a, a+3) << "\n"; 
#elif CASE == 1 
    std::cout << *std::max_element(a, a+3) << "\n"; 
#else 
    std::cout << *max_element(v.begin(), v.end()) << "\n"; 
#endif 
    return 0; 
} 

Ich habe in drei Fällen gegeben: CASE 0 schlägt fehl, da zu kompilieren es nicht so etwas wie „max_element“ ist. Ich repariere das in FALL 1, indem ich stattdessen zu "std :: max_element" ändere, und es tut kompiliert und funktioniert wie erwartet.

Interessanterweise für CASE 2 (technisch alles andere als 0 oder 1), kompiliert und funktioniert es auch. Aber CASE 2 hat das gleiche Problem wie CASE 0, also warum funktioniert es?

+1

[Argument abhängige Suche] (http://en.cppreference.com/w/cpp/language/adl). – songyuanyao

+1

@songyuanyao also hängt dieser Code von Implementierungsdetails von 'vector :: iterator' ab. Wenn es von Nicht-Klassen-Typ wäre, würde ADL –

+0

fehlschlagen, wenn ich versuche, meine eigene Version von max_element mit dem gleichen Namen zu definieren und dann mit CASE 2 oben aufzurufen, beschwert sich der Compiler, dass "call to max_element" mehrdeutig ist, was Ich gehe davon aus, dass die argumentabhängige Suche den vorhandenen max_element-Konflikt mit dem Konflikt, den ich explizit definiert habe, in Konflikt bringt. Warum darf ich das nicht tun? Bedeutet dies, dass die argumentabhängige Suche meinen nicht-std-Namespace verschmutzt? – xdavidliu

Antwort

4

Im letzten Fall, den Sie mit "CASE 2" bezeichnen, sind die Argumente Iteratoren, die für Ihre Standard-Bibliotheksimplementierung vom Typ define im Namespace std sind.

Dann Argument abhängige Lookup, häufiger als nur ADL, bekannt und heutzutage weniger häufig als Koenig-Lookup (nach Andrew Koenig) bekannt ist, findet den Namen der Funktion in diesem Namensraum.


ADL ist der Mechanismus, z.B. findet das Nicht-Mitglied operator+ für Sie, wenn Sie

std::string const a = "Blah"; 
foo(a + "Blah "); 

schreiben, aber es kann auch gewöhnliche genannten Funktionen, nicht nur Betreiber finden.

Es gibt leider keinen ähnlichen Mechanismus für den umgekehrten Weg, einen hypothetischen “ funktionsabhängigen Lookup ”, der z.B. könnte einen Typ finden, der in einer Klasse definiert ist und in einem Argumentausdruck für einen Aufruf einer Elementfunktion dieser Klasse verwendet wird.


Da ¹ std::vector erlaubt ist roh Zeiger als Iteratoren zu verwenden, werden Sie nicht garantiert, dass der Code mit einer anderen Standard-Bibliothek Implementierung arbeiten.

Hinweise:
¹ std::vector und std::basic_string Garantie zusammenhängenden internen Puffer, und dies ermöglicht rohen Zeiger als Iteratoren.

+0

" Da std :: vector erlaubt ist, rohe Zeiger als Iteratoren zu verwenden "Ich glaube nicht, dass einer der Standard-Bibliothekscontainer etwas verwendet, das von' std abgeleitet ist :: Iterator'. – user657267

+0

@ user657267: Zum Beispiel kann eine 'std :: list' keine rohen Zeiger als Iteratoren verwenden, da das Inkrementieren eines solchen Iterators in einem beliebigen Teil des Speichers landen würde (direkt nach oder innerhalb eines zugewiesenen Knotens). 'std :: vector' und' std :: basic_string' sind insofern besonders, als sie zusammenhängende interne Puffer garantieren. Und das erlaubt rohe Zeiger als Iteratoren. –

+0

Ich weiß, aber es gibt immer noch keine Anforderung, dass der typedefed Typ von 'std :: list :: iterator 'in' std' definiert ist, es sei denn, ich missverstanden die Anforderungen. – user657267

Verwandte Themen