Verständnisfragen SFINAE



  • Hallo Hustbär,

    danke für die Antworten. Punkt zwei war natürlich Quatsch, habe beim Rauslöschen ein Klammerpärchen übersehen.
    Ich verstehe die decltype-Anweisungen nicht, zb. decltype( void(container.remove_if(std::forward<Predicate>(predicate)))). Was für ein Konstrukt ist denn der void(container.remove_if(std::forward<Predicate>(predicate))) Teil? Angenommen ich hätte nur decltype(container.remove_if(std::forward<Predicate>(predicate)), dann bezeichnet decltype den Rückgabetyp des remove_if-Aufrufs. Aber wenn das noch in void(...) eingepackt wird verstehe ich das nicht mehr.
    Hast du da vllt iwo nen Artikel, der das für Idioten erklärt?


  • Mod

    void(...) ist ein functional-style cast. Also einfach ein Ausdruck, der den Operanden (hier als Ellipse dargestellt) zu void konvertiert, damit der Typ, den decltype(void(...)) bezeichnet, void ist. Das ist dieselbe Klasse von Ausdruck wie string("asdf") oder vector{1, 2, 3}. Der einzige Anlass für diesen void Cast ist die Tatsache, dass der Rückgabewert der Funktion selbst void sein muss.

    Um das ganze mal etwas kohärenter zu erklären: Wir haben eine Reihe von Methoden, um Elemente aus einem Container zu entfernen. chooser ist ein bekanntes Idiom, in welchem eine einfache Vererbungshierarchie (chooser<0> → chooser<1> → ...) eingesetzt wird, um eine Rangfolge in der overload resolution aufzuerlegen. Die optimale Methode wird vom Argument des Typen chooser<10> die minimale Anzahl an Vererbungsebenen hinaufsteigen (7) um zu chooser<3> zu konvertieren.

    Allerdings ist die Instanz dieses (und der anderen spezialisierten) Funktionstemplates nur dann ein Kandidat, wenn der Ausdruck im decltype(void(...)) wohlgeformt ist. Als erstes scheiden also alle Funktionstemplates aus, deren Deduktion aufgrund des Ausdrucks fehlerhaft ist. Dann wird (dank Symmetrie) die Funktion ausgewaehlt, deren Parameter die tiefste Vererbungsebene von choose hat.

    In C++17 koennte man das etwas eleganter schreiben, naemlich mittels if constexpr und is_detected.



  • Aaaaah, danke!
    Den function-style cast kannte ich noch nicht, jetzt ergibt das alles Sinn.



  • @DocShoe T(...) ist im Prinzip das selbe wie ((T)...)



  • Die ganzen vereinfachten Funktionen für den vollen Container, also sort(vec) anstatt sort(vec.begin(), vec.end()) etc. sollten im Standard festgelegt sein, damit nicht jeder den Mist selbst definieren muss... Sind wir mal ehrlich, wie oft musstet ihr schon Mal nur einen Teil eines Containers sortieren?



  • @HarteWare sagte in Verständnisfragen SFINAE:

    Die ganzen vereinfachten Funktionen für den vollen Container, also sort(vec) anstatt sort(vec.begin(), vec.end()) etc. sollten im Standard festgelegt sein

    Muss du halt eine ranges-Bibliothek wie range-v3 einbinden oder auf C++20 warten.



  • @wob sagte in Verständnisfragen SFINAE:

    oder auf C++20 warten.

    kommt das in C++20?



  • Ja ich freue mich auf C++20, GCC hat noch nicht mal C++17 ganz implementiert...



  • @HarteWare tatsächlich? Ich dachte eigentlich, dass inzwischen alle (GCC, Clang und MSVC) vollständigen C++17 support haben. Welche Features fehlen denn beim GCC?



  • @Unterfliege
    laut der Liste ist nicht nur GCC noch nicht "fertig".
    https://en.cppreference.com/w/cpp/compiler_support



  • @HarteWare sagte in Verständnisfragen SFINAE:

    Die ganzen vereinfachten Funktionen für den vollen Container, also sort(vec) anstatt sort(vec.begin(), vec.end()) etc. sollten im Standard festgelegt sein, damit nicht jeder den Mist selbst definieren muss... Sind wir mal ehrlich, wie oft musstet ihr schon Mal nur einen Teil eines Containers sortieren?

    der Aufruf von std::sort mit den Iteratoren ist jetzt aber auch nicht soooo der Zeitfresser... Da wäre mir eine socket-bibliothek im C++Standard wichtiger, als eine Sort-Funktion die statt 3 Parametern nur 2 braucht...



  • @It0101 sagte in Verständnisfragen SFINAE:

    der Aufruf von std::sort mit den Iteratoren ist jetzt aber auch nicht soooo der Zeitfresser...

    Es ist ja nicht nur sort. In den meisten Fällen operiere ich mit einem kompletten std::vector. Auch bei accumulate. Gut, bei lower_bound hat man öfter mal andere Grenzen. Aber sehr oft operiere ich doch auf dem ganzen Ding. Es ist auch nicht sooo der Zeitfresser, vector<int>::const_iterator in einer for-Loop zu schreiben. Dennoch ist auto wesentlich angenehmer. So auch hier. Von daher: 👍

    Ich weiß nicht, was genau von range-v3 im Standard gelandet ist, aber ich fand auch Projections ziemlich gut.



  • @Unterfliege Naja das ist halt ein Rant von mir, weil ich mal gerne std::from_chars verwendet hätte und dann mein Compiler mich angemault hat.

    Was mich auch etwas nervt: Sachen wie std::fstream etc. haben keinen c-tor für std::string_view...