Template resolution
-
template< typename T, typename Enable = void > struct converter; // wird zu template <typename T_Fun, typename Enable_Fun = int > // int statt void, weil void kein Funktionsparameter sein kann, hat sonst keine weitere Bedeutung struct converter_fun(T_Fun, Enable_Fun = 0); template< typename T > struct converter< T, typename enable_if< irgendwas >::type > { }; // wird zu template <typename T_Fun, typename Enable_Fun = int> struct converter_fun(T_Fun, int = typename enable_if<irgendwas,int>::type{});Das ist doch Unsinn! Irre ich mich, oder sollte das nach 14.5.5.2 nicht so aussehen:
template< typename T, typename Enable = void > struct converter; // wird zu template <typename T, typename Enable = void > struct converter_fun( converter<T, Enable> ); template< typename T > struct converter< T, typename enable_if< irgendwas >::type > {}; // wird zu template <typename T> struct converter_fun( converter<T, typename enable_if<irgendwas>::type> );
-
Arcoth schrieb:
Das ist doch Unsinn!
Stimmt. Passiert, wenn man beim Schreiben unterbrochen wird. Normalerweise lese ich sowas erst nochmal nach.
Ist normalerweise auch nichts, was im Kopf behalten muss, Faustregeln reichen fast immer aus.
-
Hallo camper,
vielen Dank erstmal für die Ausführlichkeit, das macht es alles viel klarer.
Ich hatte hier bis eben folgendes stehen:template <typename T> struct default_converter < T, typename std::enable_if< detail::is_integer_parameter<T>::value > > : integer_converter< T >Und das hat irgendwie in 95% der Fälle funktioniert, war das vielleicht ein Fehler von VC++?
Vor allem hatte ich (siehe Post im "Rund um die Programmierung") damit das Problem, dass in meiner Veränderung
template <typename T> struct default_converter < T, typename std::enable_if< detail::is_integer_parameter<T> > > : integer_converter< typename detail::disallow_nonconst_reference<T>::type >, wobei in dem disallow_nonconst_reference ein static_assert verborgen ist, das static_assert verschluckt wurde, und die ganze Sache durch SFINAE veworfen wurde.
Aber
template <typename T> struct default_converter < T, typename std::enable_if< detail::is_integer_parameter<T>::value >::type > : integer_converter< typename detail::disallow_nonconst_reference<T>::type >funktioniert laut VC++-Ergebnis jetzt genau so, wie ich es mir von Anfang an gewünscht hatte, das static_assert vom disallow_nonconst_reference springt an, anstatt dass die Spezialisierung verworfen wird und das unspezialisierte Template ausgewählt wird. Ich hatte schon befürchtet, dieser Enable-If-Trick würde das verhindern und ich müsste das gesamte System umstellen.

-
In dem 2. Beispiel fehlt das "::value", das habe ich hier verschluckt, sorry.
-
::type
ist wichtig. Der Type enable_if<x, y> existiert ja immer, für irgendwelche x,y.
Member type dagegen nur, wenn x wahr ist.
-
Ja genau! Wenn ich mir das jetzt halt nach Deinen Ausführungen so anschaue, kann ich mir überhaupt nicht vorstellen, wie das überhaupt mal halbwegs funktioniert haben soll. Aber ich habe bei dem fehlerhaften Konstrukt tatsächlich mit Typen, die kein "integer argument" waren, das unspezialisierte Template getroffen.

-
decimad schrieb:
Ja genau! Wenn ich mir das jetzt halt nach Deinen Ausführungen so anschaue, kann ich mir überhaupt nicht vorstellen, wie das überhaupt mal halbwegs funktioniert haben soll. Aber ich habe bei dem fehlerhaften Konstrukt tatsächlich mit Typen, die kein "integer argument" waren, das unspezialisierte Template getroffen.

Vielleicht existiert ja detail::is_integer_parameter<T>::value nicht in allen Fällen? Sonst minimales Beispiel bitte.
-
Ja, ich bin schon dabei, eines zu konstruieren, weil ich total baff bin... Vielleicht schlägt das aber Fehl und irgendwas anderes ist hier total faul. is_integer_parameter<T>::value existiert auf jeden Fall immer, soviel kann ich sagen.
-
Jetzt wird es mir klar.
Aus absolut nachzuvollziehenden Gründen habe ich niemals die Spezialisierung getroffen (schließlich war enable_if<...> ja nicht "void") und das während der Testfälle, bei denen ich ja sicherstellen wollte, dass ich die Spezialisierung nicht treffe, bzw. dass die Spezialisierung mit static_assert fehlschlagen solle. Dabei konnte mir natürlich auch nicht auffallen, dass ich sie auch niemals in den Fällen getroffen hätte, in denen der Typ ein "akzeptierter" ist.
Jetzt frage ich mich nur, wie lange dieses ::type da inzwischen fehlte Oo. Weil ich noch vor ein paar Tagen auf jeden Fall die Spezialisierung getroffen hatte. Mannmannmann. Ditsch. Ditsch. Ditsch.
-
Und jetzt verstehe ich auch den SFINAE-Trick in diesem Fall. enable_if defaulted den zweiten Typ-Parameter auch zu void (vermutlich weil man das oft als Rückgabetyp von Funktionen hernimmt, oder als Pseudo-Argument zu eben solchen?), das heißt, der Template-Prozessor will "T, void" gegen "T, enable_if< bedindung, void >::type" matchen und sieht, das passt, oder aber es gibt kein type, dann schlägt SFINAE zu.