Spezialisierung einer Methode einer Template-Klasse



  • Hallo Forum,

    ich versuche von einer Template-Klasse eine Methode zu spezialisieren. Dabei habe ich mich an der Beschreibung auf cppreference orientiert.
    Irgendetwas mache ich aber offensichtlich falsch, denn ich bekomme einen Linker-Fehler (siehe folgendes Minimalbeispiel):

    error LNK2005: "public: int __cdecl Foo<int>::FooMethod(int const &)const " (?FooMethod@?$Foo@H@@QEBAHAEBH@Z) already defined in Bar.obj
    
    // Foo.h
    #pragma once
    
    template<typename T>
    class Foo
    {
    public:
       T FooMethod(const T& val) const;
    };
    
    template<typename T>
    T Foo<T>::FooMethod(const T& val) const
    {
       return val;
    }
    
    // Spezialisierung
    template<>
    int Foo<int>::FooMethod(const int& val) const
    {
       return 42;
    }
    
    // bar.h
    #pragma once
    
    class Bar
    {
    };
    
    // bar.cpp
    #include "Bar.h"
    #include "Foo.h"
    
    // main.cpp
    #include "Foo.h"
    #include "Bar.h"
    
    int main()
    {
       return 0;
    }
    

    Wenn ich die Spezialisierung auskommentiere, verschwindet der Fehler.
    Mir ist zum einen nicht klar, warum es hier überhaupt zum Linker-Fehler kommt. Vor allem wüsste ich aber gerne wie die Spezialisierung korrekt aussehen müsste. Kann hier jemand ein wenig Licht ins Dunkel bringen?



  • Hallo,

    deine Spezialisierung hängt überhaupt nicht mehr von einem template-Parameter ab. Ist also so gesehen eine ganz "normale" Funktion und muss ins cpp oder inline sein.



  • Danke für die schnelle Antwort, das leuchtet ein.
    Ich habe Foo jetzt folgendermaßen geändert. Funktioniert offenbar, so ganz vertraut liest es sich für mich aber nicht...

    // foo.h
    #pragma once
    
    template<typename T>
    class Foo
    {
    public:
       T FooMethod(const T& val) const;
    };
    
    template<typename T>
    T Foo<T>::FooMethod(const T& val) const
    {
       return val;
    }
    
    template<>
    int Foo<int>::FooMethod(const int& val) const;
    
    // foo.cpp
    #include "foo.h"
    
    int Foo<int>::FooMethod(const int& val) const
    {
       return 42;
    }
    

    Die Deklaration der Spezialisierung steht also außerhalb der Klasse im Header?
    Die Implementation steht im cpp (wenn ich inline nicht möchte) und offensichtlich muss ich dort "template<>" nicht wiederholen?
    Passt das so?



  • @LennyS GCC meint das template<> ist nötig:

    <source>:18:5: error: specializing member 'Foo<int>::FooMethod' requires 'template<>' syntax
    
       18 | int Foo<int>::FooMethod(const int& val) const
    
          |     ^~~~~~~~
    
    Compiler returned: 1
    

    Clang ist der selben Meinung.

    Davon abgesehen sollte es passen. Oder du machst es so wie du es hattest (=Definition direkt im Header-File), aber schreibst einfach noch inline dazu.



  • Alles klar, danke für die Rückmeldung! Dann ist entweder Visual Studio toleranter oder die Settings sind weniger streng. Ich werde es jedenfalls wieder ergänzen.


Anmelden zum Antworten