std::function von Template Methoden in Template Klassen



  • Hallo zusammen,

    ich hab mein Problem mal etwas vereinfacht:

    #include <functional>
    
    template <typename T>
    struct ClassA
    {
        template <typename U>
        static T foo(int) { return T(U(47)); }
    };
    
    template <typename T>
    struct ClassB
    {
        template <typename U>
        static T foo(float) { return T(U(27)); }
    };
    
    // ClassC, ClassD, ClassE, ...
    
    template <typename T>
    struct Test
    {
        std::function<T(int)> classAFun;
        std::function<T(float)> classBFun;
    
        template <typename U>
        static Test<T> create()
        {
            return Test<T>{ClassA<T>::foo<U>,
                           ClassB<T>::foo<U>}; // error
        }
    };
    
    int main()
    {
        Test<int> t1{ClassA<int>::foo<double>,
                     ClassB<int>::foo<double>}; // ok
    
        Test<int> t2 = Test<int>::create<double>();
    }
    

    Fehlermeldung (kompiliert mit g++ -std=c++17 test.cpp, g++ version: 9.3.0):

    test.cpp: In static member function ‘static Test<T> Test<T>::create()’:
    test.cpp:28:23: error: expected primary-expression before ‘{’ token
       28 |         return Test<T>{ClassA<T>::foo<U>,
          |                       ^
    test.cpp:28:23: error: expected ‘;’ before ‘{’ token
       28 |         return Test<T>{ClassA<T>::foo<U>,
          |                       ^
          |                       ;
    

    Warum funktioniert das wenn die Template Variablen explizit angegeben werden (main Methode Zeil 35) und warum nicht in der create Methode (Zeile 28)?

    Kennt jemanden eine Lösung für die create Methode?

    Danke



  • @klaus sagte in std::function von Template Methoden in Template Klassen:

        template <typename U>
        static Test<T> create()
        {
            return Test<T>{ClassA<T>::foo<U>,
                           ClassB<T>::foo<U>}; // error
        }
    

    Hier ist nicht bekannt wie die Klassen ClassA<T> und ClassB<T> aufgebaut sind da diese vom (unbekannten) Typ T abhängig sind (ClassA<T> und ClassB<T> sind "dependent types"). Du musst daher Member die selbst wieder ein Template sind mit dem Keyword template kennzeichnen, genau so wie du Typ-Member mit dem Keyword typename kennzeichnen müsstest:

        template <typename U>
        static Test<T> create()
        {
            return Test<T>{ClassA<T>::template foo<U>,
                           ClassB<T>::template foo<U>}; // error
        }
    


  • BTW: Du hast das Beispiel schonmal gut gekürzt, das sollte wenn man es nicht sofort sehen/fixen kann immer der erste Schritt sein. 👍 Was danach oft hilft ist das ganze einem anderen Compiler zu füttern. Was mit Services wie godbolt.org sehr schön geht.

    Clang sagt da z.B.:

    <source>:28:35: error: use 'template' keyword to treat 'foo' as a dependent template name
            return Test<T>{ClassA<T>::foo<U>,
                                      ^
                                      template 
    <source>:29:35: error: use 'template' keyword to treat 'foo' as a dependent template name
                           ClassB<T>::foo<U>}; // error
                                      ^
                                      template 
    

    Siehe https://godbolt.org/z/jca7jj



  • Vielen Danke für die schnelle Antwort, Lösung und den Tipp 🙂


Log in to reply