SFINAE Compiler Probleme

7

Der folgende Code von mir sollte erkennen, ob T begin und end Methoden hat:

%Vor%

Und hier ist ein Testcode:

%Vor%

In g ++ 4.5.1 lautet die Ausgabe 1 1 1 1 . In Visual Studio 2008 lautet die Ausgabe jedoch 1 1 0 0 . Habe ich etwas falsch gemacht, oder ist das einfach ein VS 2008 Bug? Kann jemand an einem anderen Compiler testen? Danke!

    
fredoverflow 03.12.2010, 17:00
quelle

5 Antworten

1

Stephan T. Lavavej hat das um zu sagen:

  

Bitte beachten Sie, dass es technisch verboten ist, die Adresse einer Memberfunktion der Standardbibliothek zu übernehmen. (Sie können überladen werden, wodurch &foo::bar mehrdeutig wird und sie zusätzliche Standardargumente haben können, um Versuche zu vereiteln über static_cast zu disambiguieren.)

Ich denke also, ich werde die einfachere Version verwenden, die nur nach dem verschachtelten const_iterator -Typ sucht.

    
fredoverflow 10.12.2010, 13:25
quelle
12

Also, hier geht es darum, diese Dinge zu debuggen.

Geben Sie zuerst die negative Alternative aus, damit Sie einen Fehler erhalten und nicht nur eine Abweichung. Als nächstes versuchen Sie, den Typ, den Sie in die Funktion einfügen, mit einem der Elemente, die nicht funktionieren, zu instanziieren.

Bei diesem Schritt konnte ich Ihr sfinae-Objekt instantiieren, aber es funktionierte immer noch nicht. Dadurch weiß ich, dass es sich um einen VS-Fehler handelt, also stellt sich die Frage, wie man es beheben kann.

VS scheint Probleme mit SFINAE zu haben, wenn Sie so behandelt werden, wie Sie sind. Es funktioniert besser, wenn Sie Ihr sfinae-Objekt einpacken. Ich habe das so gemacht:

%Vor%

Hat immer noch nicht funktioniert, aber ich habe zumindest eine sinnvolle Fehlermeldung bekommen:

error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::_Tree_const_iterator<_Mytree> (__thiscall std::set<_Kty>::* )(void) const'

Das lässt mich wissen, dass &U::end nicht ausreicht, damit VS sagen kann, welches Ende () ich möchte. Ein static_cast behebt das:

%Vor%

Setzen Sie alles wieder zusammen und führen Sie Ihr Testprogramm darauf aus ... Erfolg mit VS2010. Du findest vielleicht, dass ein static_cast eigentlich alles ist, was du brauchst, aber ich habe dir das überlassen, um es herauszufinden.

Ich nehme an, die wirkliche Frage ist jetzt, welcher Compiler richtig ist? Meine Wette ist auf die eine, die konsistent war: g ++.

Bearbeiten: Jeesh ...

%Vor%     
Crazy Eddie 03.12.2010 17:56
quelle
5

Warum gehen Sie all diese Bemühungen? Wenn Sie überprüfen möchten, ob U::begin() existiert, warum nicht versuchen?

%Vor%

Zusätzlich zur Überprüfung auf das Vorhandensein von U::begin() und U::end() wird auch überprüft, ob sie etwas zurückgeben, das in ein const_iterator konvertierbar ist. Es vermeidet auch die von Stephan T. Lavavej hervorgehobenen Fallstricke, indem es einen Aufrufausdruck verwendet, der unterstützt werden muss, anstatt eine bestimmte Signatur anzunehmen.

[Bearbeiten] Entschuldigung, dies beruhte auf der Template-Instanziierung von VC10. Besserer Ansatz (setzt die Existenzprüfung der Argumenttypen, die tun am Überladen teilnehmen):

%Vor%     
MSalters 10.12.2010 15:21
quelle
3

Mit C ++ 11 gibt es jetzt bessere Möglichkeiten, dies zu erkennen. Anstatt sich auf die Signatur von Funktionen zu verlassen, rufen wir sie einfach in einem Ausdruck SFINAE-Kontext auf:

%Vor%

Live-Beispiel auf Ideone. Die Parameter int und long dienen nur dazu, die Überladungsauflösung zu disambiguieren, wenn der Container beides bietet (oder wenn iterator ist typedef const_iterator iterator , wie std::set erlaubt ist) - literal 0 hat den Typ int und erzwingt die erste Überladung.

    
Xeo 08.02.2012 16:03
quelle
1

Das sollte wahrscheinlich ein Kommentar sein, aber ich habe nicht genug Punkte

@MSalters

Obwohl Ihr is_container (fast) funktioniert und ich Ihren Code selbst verwendet habe, habe ich zwei Probleme darin entdeckt.

Erstens wird der Typ deque<T>::iterator als Container erkannt (in gcc-4.7). Es scheint, dass deque<T>::iterator begin / end members und const_iterator type definiert hat.

Das zweite Problem ist, dass dieser Code laut GCC-Devs ungültig ist. I qoute: -Werte von Standardargumenten sind nicht Teil des Funktionstyps und nehmen nicht an der Ableitung teil. Siehe GCC-Fehler 51989

Ich verwende derzeit dies (nur C ++ 11) für is_container<T> :

%Vor%     
Leonid Volnitsky 08.02.2012 15:19
quelle