Praktische Verwendung von SFINAE



  • Hallo zusammen,

    ich frage mich gerade, wann man in der Praxis SFINAE verwendet.
    Ich möchte euch jetzt auch nicht durch irgendwelche Ideen meinerseits beeinflussen.

    Also ganz simpel:
    Wann verwendet ihr SFINAE?

    Gruß,
    XSpille



  • XSpille schrieb:

    Also ganz simpel:
    Wann verwendet ihr SFINAE?

    Nun gut, du hast es so gewollt:
    -Wenn es sinnvoll ist.
    -Wenn es nicht anders geht.
    -Wenn man es braucht.

    Also bisher habe ich es nie wirklich gebraucht, soweit ich mich erinnern kann, außer für Sachen, die ich dann doch nicht gebraucht habe (ich programmiere aber auch erst seit ca. 2 Jahren).



  • Eigentlich nie.



  • Eigentlich manchmal.
    Wenn auch indirekt mit boost::enable_if.



  • Template Metaprogrammierung. Sonst eher selten.



  • XSpille schrieb:

    Wann verwendet ihr SFINAE?

    Du meinst, wann wir es "ausnutzen" ? 😉

    Als Autor des einen oder anderen Funktionstemplates verwende ich das schonmal, um ein solches Template aus dem Overloadset rauszuschmeißen, wenn eine bestimmte Bedingung nicht gilt. Damit kann man Mehrdeutigkeiten umgehen und Compile-Zeit-Fehlermeldungen kürzen. Also, für Bibliotheksentwickler ist das interessant.

    Du kannst ja mal in einem der letzten C++11 Entwürfe im zweiten Teil über die Standardbibliothek nach der Wendung "shall not participate in overload resolution" suchen. Du wirst zig solcher Stellen finden. Und in jedem dieser Fälle werden die Leute, die die Standardbibliothek implementieren, SFINAE ausnutzen -- zumindest so lange, wie sie noch keine passende "Compiler-Magie" verwenden können; denn für das "shall not participate in overload resolution" gibt es in Standard-C++ (noch) kein extra Sprachfeature, sondern eben nur den SFINAE-Effekt.

    Beispiel:

    #define REQUIRES(...) ,class=typename std::enable_if<(__VA_ARGS__)>::type
    
    template<class T>
    class shared_ptr
    {
    public:
      :::
    
      template<class U
        REQUIRES( is_convertible<U*,T*>::value )
      >
      shared_ptr(shared_ptr<U> const& x)
      {
        :::
      }
    
      :::
    };
    
    struct base {};
    struct derived : base {};
    struct other {};
    
    void overload(shared_ptr<base>);
    void overload(shared_ptr<other>);
    
    int main() {
      auto sp = make_shared<derived>();
      overload(sp); // Welche Funktion ?
    }
    

    "ohne SFINAE" --> Compilezeitfehler, da mehrdeutig

    "mit SFINAE" --> Eindeutig, shared_ptr<derived> kann nur nach shared_ptr<base> konvertiert werden und nicht nach shared_ptr<other>. Das ist hier schon vor der Overload Resolution klar.

    (Dieses Makro ist nicht auf meinen Mist gewachsen)



  • Danke euch...

    @krümelkacker: Die schwere Kost werde ich mir morgen mal genauer angucken 🙂



  • Würde SFINAE nicht auch bei Dingen wie std::algorithm Sinn machen, um festzustellen, ob der Iterator Random Access, Bidirektional oder Forward ist?



  • Da ein STL-kompatibler Iterator entsprechende Informationen über sich via std::iterator_traits verrät, unterscheidet man Iterator-Kategorien hauptsächlich per "tag dispatching". Das hat dann aber nichts mit SFINAE zu tun.



  • XSpille schrieb:

    Die schwere Kost werde ich mir morgen mal genauer angucken 🙂

    Ich konnt's mir nicht ganz verkneifen, eine moderne C++2011 Variante davon vorzustellen. In C++2003 muss man das so schreiben:

    template<class U>
      shared_ptr(shared_ptr<U> const& x,
        typename boost::enable_if<boost::is_convertible<U*,T*> >::type* =0)
      {
        :::
      }
    


  • krümelkacker schrieb:

    Ich konnt's mir nicht ganz verkneifen...

    Ich finds gut, wenn du (in meinen Augen) anspruchsvollen Code postest 👍


Anmelden zum Antworten