[SFINAE] Compile error mit std::enable_if und std::is_arithmetic



  • Hi, ich wollte eine Funktion mittels SFINAE so überladen, dass sie alle arithmetischen Typen akzeptiert. Mein Ansatz sieht wie folgt aus:

    #include <type_traits>
    #include <iostream>
    
    void foo(std::string const & value) {
        std::cout << value << " is a string\n";
    }
    
    template <class T>
    void foo(typename std::enable_if<std::is_arithmetic<T>::value, T>::type value) {
        std::cout << value << " is arithmetic\n";
    }
    
    int main() {
        foo("hallo welt");
        foo(124);
        foo(34.5);
    }
    

    Allerdings lande ich mit clang 3.5 in einer Sackgasse:

    test.cpp:15:5: error: no matching function for call to 'foo'
        foo(124);
        ^~~
    test.cpp:4:6: note: candidate function not viable: no known conversion from 'int' to 'const std::string'
          (aka 'const basic_string<char>') for 1st argument
    void foo(std::string const & value) {
         ^
    test.cpp:9:6: note: candidate template ignored: couldn't infer template argument 'T'
    void foo(typename std::enable_if<std::is_arithmetic<T>::value, T>::type value) {
         ^
    

    Mit GCC 4.8 läuft es ähnlich - nur weniger aussagekräftig.

    Habe ich irgendwo einen Denk-/Tippfehler - oder sind CLANG und GCC diesbezüglich noch nicht so weit? Prinzipiell sollte die Argumentliste für arithmetische Typen well-formed und für sonstige Typen ill-formed sein, so dass ich dank SFINAE unter'm Strich meine Funktion für alle arithmetischen Typen überladen habe(n müsste).. ^^

    LG Glocke


  • Mod

    template <class T> 
    void foo(typename std::enable_if<std::is_arithmetic<T>::value, T>::type value)
    

    Weiter habe ich gar nicht geschaut. Der Fehler fällt sofort ins Auge: Der Parametertyp ist ein non-deduced context, d.h. Template-Argumente werden dafür nicht deduziert. Mach einfach

    template <class T> 
    typename std::enable_if<std::is_arithmetic<T>::value>::type foo(T value)
    

    draus.


  • Mod

    Glocke schrieb:

    Habe ich irgendwo einen Denk-/Tippfehler

    ja. Das enable_if-Konstrukt kann nicht dazu hergezogen werden, das Templateargument zu deduzieren.
    Es wird immer ein Argument benötigt, aus dem heraus eine Deduktion möglich it, und enable_if taucht an anderer Stelle auf (weiteres Funktionsargument, Rückgabetyp oder zus. Templateparameter) so dass bei einem unzulässigen (bereits deduzierten) Templateparameter die Deklaration ungültig wird.



  • Arcoth schrieb:

    template <class T> 
    typename std::enable_if<std::is_arithmetic<T>::value>::type foo(T value)
    

    Ok danke, das funktioniert erstmal 🙂
    Aber dabei scheint mein Return type verloren zu gehen, oder? Angenommen ich möchte einen bool liefern.. wie genau müsste ich die Signatur dann verändern?
    /EDIT: Also geht das nicht? XD Welche Möglichkeiten bleiben mir dann?


  • Mod

    template <class T> 
    typename std::enable_if<std::is_arithmetic<T>::value, bool>::type foo(T value)
    

    Siehe auch die Referenz zu enable_if .


  • Mod

    enable_if hat einen zweiten Templateparameter.



  • Arcoth schrieb:

    template <class T> 
    typename std::enable_if<std::is_arithmetic<T>::value, bool>::type foo(T value)
    

    Siehe auch die Referenz zu enable_if .

    Danke, irgendwie hab ich das in der Dokumentation wohl überlesen 😃
    thx - kann geschlossen werden

    LG Glocke


Anmelden zum Antworten