2012-03-28 9 views
4

vor einiger Zeit bemerkte ich, dass in Visual C++ 10 ADL fehlschlägt, wenn mindestens eines der Argumente ein Lambda ist.ADL schlägt fehl, wenn Lambda-Argumente vorhanden sind?

std::vector<float> vec; 
for_each(begin(vec), end(vec), [](float) {}); 

Die oben nicht auf VC++ 10 und 11 (Beta) (Beginn und Ende gefunden über ADL) zu kompilieren. Wenn ich die Lambda-Funktion in eine reguläre freie Funktion umwandele, funktionieren die Dinge wie erwartet.

Ich habe auf Herb Sutters Blog einmal gefragt und auch ein paar Beiträge auf msdn connect gelesen und die üblichen Antworten waren: Dies ist ein Fehler, wir haben nicht den neuesten Standard der Lambdas implementiert, die - zu dieser Zeit - recht war verständlich. Die Dinge waren noch nicht in einer gebackenen Form. Auf MS connect gab es auch beunruhigende Kommentare, dass dies nicht für die nächste Version behoben werden wird, d. H. Vc 11.

Meine Frage ist, ist dieser Code erwartet unter dem C++ 11-Standard arbeiten? Das kann ich mir nicht vorstellen. Muss ich wirklich for_each und andere Algorithmen mit std :: voranstellen, wenn ich lambdas verwende? Ich vermute irgendwie, dass dieses Verhalten nicht nach vC++ 11 Release ändern wird.

+1

welche freie Funktion tun Sie nutzen? –

+0

etwas so einfach wie void f (float) {} funktioniert sogar. oder das Lambda außerhalb des Funktionsaufrufs deklarieren: auto f = [] (float) {}; –

Antwort

1

Das ist perfekt gültigen Code. Jeder fehlerfreie Compiler kann sie kompilieren. Aber da MSVC einen Fehler hat und daher nicht in der Lage ist, die Funktion über ADL zu durchsuchen, sollten Sie sich vielleicht nicht auf ADL verlassen und ihn stattdessen mit std:: qualifizieren, damit der Compiler die Funktion finden kann.

+0

das bestätigt, was ich denke. Ich verstehe auch nicht, warum die Kombination von Lambda-Argumenten und Nicht-Lambda-Argumenten ADL deaktivieren sollte. nicht sicher, ob ich die offizielle Microsoft-Antwort mag (instanziieren Sie das Lambda woanders oder qualifizieren Sie sich mit Std: :);) –

+0

@Martin: Nein, 'vector :: iterator' darf' T * 'sein (ich vermute das ist genau das Problem). Obwohl die Antwort von @ refp ein bisschen lang ist und Ihren Verdacht nicht bestätigt, ist sie korrekt. Obwohl ich nicht erklären kann, warum es mit einer freien Funktion funktioniert, die nicht über 'std' Typen parametrisiert ist. – Potatoswatter

+1

@Martin Bitte setzen Sie das grüne Häkchen auf die Antwort von refp. –

15

Der Standard garantiert nicht, was Sie wollen, würde es ..

Mit dem unten im Auge erkennen, können wir leicht, dass es nichts garantiert ist, dass ADL in Fällen ähnlich dem Beispiel funktionieren würde zur Verfügung gestellt in deinem Beitrag.


  • std::begin (c)/std::end (c)

    Die Funktionen werden in dem Standard als das unten Zitat beschrieben:

    template <class C> auto begin(C& c) -> decltype(c.begin()); 
    template <class C> auto end(C& c) -> decltype(c.end()); 
    

    Obwohl die Container<...>::iterator (die der Rückkehr-Typ c.begin() ist) ist, ein implementierungsdefinierter Typ.

    Mehr über die Sache kann und 23.3.6.1/2 Klasse Vorlage Vektor (oder jede andere Vorlage STL-Container) bei 24.5.6 Bereichszugriffs lesen auf werden.

  • [](){} - Lambda-Ausdrücke

    Ein Lambda ist eine Implementierung definiert Art, es gibt nichts in der Norm besagt, dass das resultierende Objekt eines Typs sein, die unter Namespace std ist .

    Es kann ziemlich viel existieren, wo immer es will, solange es die anderen Regeln bestätigt, die durch den Standard aufgestellt werden.



zu lang; Lesen Sie nicht

Die Typen von denen std::begin/std::end/a lambda-expression Ausbeuten sind nicht werden unter Namespace std garantiert, deshalb ist ADL nicht in Kick garantiert.

+3

@David: Nein, die Frage ist genau über 'for_each'. Es sagt sogar, dass "begin" und "end" ohne Probleme gefunden werden. Ich denke, die meisten Leute haben die Frage nicht richtig gelesen. Für refp: +1 ist dies die richtige Antwort. – Xeo

+0

@Xeo: Ich dachte, dass ADL 'beginnen' und 'Ende' nicht auflösen konnte. In jedem Fall gibt es, da es im Standard keine Garantie dafür gibt, dass sich die Iteratoren in "std" befinden, immer noch einen Fehler, wenn man "for_each" im Falle des Lambda nicht findet (unter der Annahme, dass "std :: vector" <> :: iterator 'ist in' std' definiert oder in ADL 'for_each' gefunden, wenn das Lambda durch einen Funktionsaufruf ersetzt wird (wenn' std :: vector <> :: iterator' nicht in 'std definiert ist '). –

+0

Zur Klarstellung: Anfang und Ende werden über ADL sowohl in vC++ 10 als auch 11 beta korrekt aufgelöst. Meine Frage wurde darauf gerichtet, warum ADL für for_each (oder irgendeinen anderen std-Algorithmus) fehlschlägt, wenn es eine Kombination von Typen gibt, die aus dem Namespace std * und * einem oder mehreren lambdas stammen. Ich denke, dass vC++ ADL deaktiviert, wenn es Lambda-Argumente gibt. Beachten Sie, dass, wenn Sie for_each ein Lambda übergeben, das außerhalb des Funktionsaufrufs for_each deklariert wird, ADL funktioniert (was derzeit der offizielle Workaround von Microsoft ist). –

Verwandte Themen