2015-09-20 4 views
6

Dies ist eine Erweiterung auf diese Frage ab 2011: Range-based for loops and ADLBereich Basierte For-Schleife und ADL

mit Visual Studio 2015, ich bin nicht in der Lage eine bereichsbasierte for-Schleife für einen benutzerdefinierten Container mit Argument zu machen Abhängige Suche (ADL).

ich einen sehr einfachen Testfall unten mit einem benutzerdefinierten Container gemacht habe:

#include <vector> 

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 
} 

template <typename T> 
typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
{ 
    return foo.values.begin(); 
} 

template <typename T> 
typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
{ 
    return foo.values.end(); 
} 

Mit diesem Behälter und ADL, der folgende Test kompiliert völlig in Ordnung:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto it = begin(values); it != end(values); ++it) 
    { 
     ... 
    } 

    return 0; 
} 

wie es sollte. Ich bin mir nicht sicher, ob ADL hier überhaupt verwendet wird, aber egal, es macht Sinn. Von MSDN documentation haben wir:

Denken Sie daran, diese Fakten über bereichsbasierte für:

  • automatisch erkennt Arrays.

  • Erkennt Container, die .begin() und .end() haben.

  • Verwendet die Argument-abhängige Suche begin() und end() für alles andere.

Von dem, was ich von ADL verstehen, und die Dokumentation oben, sollte die folgende auch kompilieren:

int main(int argc, char* argv[]) 
{ 
    Foo::Container<int> values; 

    for (auto value : values) 
    { 
     ... 
    } 

    return 0; 
} 

Aber es funktioniert nicht. Stattdessen erhalte ich folgende Fehler:

error C3312: no callable 'begin' function found for type 'Foo::Container<int>' 
error C3312: no callable 'end' function found for type 'Foo::Container<int>' 

Also, was ist hier los? Ist meine Interpretation von ADL falsch oder ist das ein Fehler mit MSVC 14.0 Compiler?

+1

IINM 'begin()' und 'end()' sollten in 'Foo' stehen. – Quentin

+0

Dies hängt nicht von ADL ab, da 'begin' und' end' nicht im Namespace 'Foo' sind, aber es scheint in gcc gut zu funktionieren: http://coliru.stacked-crooked.com/a/12047609140d05a9. Wenn Sie 'begin' und' end' ändern, um stattdessen einen 'const'ref zu verwenden, funktioniert das dann auf MSVC? – rici

+0

@rici, Nein, tut es nicht. Ich frage mich, warum es in GCC funktioniert, wenn Pawlos Antwort richtig ist. Welcher Compiler ist der richtige ?!:) – Zeenobit

Antwort

7

Sie müssen begin und end in Foo Namespace platzieren, damit ADL funktioniert. Dies liegt daran, dass ADL in Namespaces der entsprechenden Argumente nach den Definitionen von begin und end sucht.

namespace Foo 
{ 
    template <typename T> 
    class Container 
    { 
    public: 

     std::vector<T> values; 
    }; 

    template <typename T> 
    typename std::vector<T>::iterator begin(Foo::Container<T>& foo) 
    { 
     return foo.values.begin(); 
    } 

    template <typename T> 
    typename std::vector<T>::iterator end(Foo::Container<T>& foo) 
    { 
     return foo.values.end(); 
    } 
} 

UPD: Der Grund, warum begin und end von globalem Namensraum sind nicht wegen der aktualisierten Norm betrachtet ist zu sagen, dass begin und end sind in dem zugehörigen Namensraum, sondern gewöhnlicher unquali fi ziert Lookup durchgeführt wird, nicht nachgeschlagen. Dies ist eine Folge der Fehlerbehebung im Standard (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1442).

+0

Es sollte auch mit 'begin' und' end' funktionieren, die im globalen Namespace definiert sind. Warum nicht? – rici

+0

@rici Dies ist, weil gewöhnliche unqualifizierte Nachschlagen (Nachschlagen in globalen Namespace) nicht gemäß aktualisierten Standard durchgeführt wird: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defekten.html # 1442 –

+0

@ PavloMur Danke für die Klarstellung. – Zeenobit