[Gelöst]Compiler(GCC) findet Speialisierung von funktionstemplate nicht, wenn diese wiederum ein template part enthält



  • Hi,

    folgender code wird problemlos vom C++ Compiler von Visual Studio 2012 übersetzt.

    #include <iostream>
    #include <vector>
    
    class test
    {
    public:
        template <typename T>
        void print(T& value);
    
        void printRaw(void* data)
        {
            std::cout<<"data: "<<data<<"\n";
        }
    };
    
    namespace dummy
    {
        template<typename T>
        void print(test& tt, T& value)
        {
            static_assert(sizeof(T) == 0, "unimplemented");
        }
    }
    
    //namespace dummy
    //{
    //    template<typename T>
    //    void print(test& tt, std::vector<T>& value)
    //    {
    //        size_t size = value.size();
    //        tt.print(size);
    //    }
    
    //}
    
    template <typename T>
    void test::print(T& value)
    {
        dummy::print(*this, value);
    }
    
    namespace dummy
    {
        template<>
        void print(test& tt, int& value)
        {
            tt.printRaw(&value);
        }
    
        template<>
        void print(test& tt, size_t& value)
        {
            tt.printRaw(&value);
        }
    
        template<typename T>
        void print(test& tt, std::vector<T>& value)
        {
            size_t size = value.size();
            tt.print(size);
        }
    }
    
    int main()
    {
        test testInst;
    
        int t = 100;
        testInst.print(t);
    
        std::vector<float> ttt;
        testInst.print(ttt);
    
        return 0;
    }
    

    Nur dem gcc (4.6 und 4.8 getestet mit aktiver c++11 Unterstützung) lässt sich der code nicht übersetzen.
    Für den Aufruf

    testInst.print(std::vector<T>)
    

    findet der gcc scheinbar nur das funktionstemplate

    template<typename T>
        void print(test& tt, T& value)
    

    , welche aber nur dazu dient einen compiler Fehler zu generieren, wenn für einen bestimmten Typ keine Spezialisierung dieses templates existiert.

    Wenn ich aber die zeilen 25-34 anstelle der zeilen 58 - 63 aktiviere, dann funktioniert das übersetzen auch mit dem GCC.

    Nur das ist nicht gewollt. Denn dadurch müsste jede Spezialisierung bereits vor der Definierung von

    template <typename T>
    void test::print(T& value)
    

    bekannt sein.

    Gibt es eine Möglichkeit den code, so wie er oben steht, auch mit dem GCC zu übersetzen?
    Oder funktioniert das so eventuell überhaupt nicht laut c++ standard?

    Eventuell müsste das funktionstemplate anders deklariert werden, damit auch Spezialisierungen gefunden werden, welche wiederum selbst einen template parameter definieren.



  • firefly schrieb:

    Oder funktioniert das so eventuell überhaupt nicht laut c++ standard?

    Exakt.Nur Funktionen die in Zeile 41 bekannt sind, kommen für den lookup in Frage. Der VC erlaubt da mehr als der Standard erlaubt.

    Im Zweifelsfall musst du Klassenspezialisierungen benutzen.



  • otze schrieb:

    firefly schrieb:

    Oder funktioniert das so eventuell überhaupt nicht laut c++ standard?

    Exakt.Nur Funktionen die in Zeile 41 bekannt sind, kommen für den lookup in Frage. Der VC erlaubt da mehr als der Standard erlaubt.

    Im Zweifelsfall musst du Klassenspezialisierungen benutzen.

    Meinst du damit, dass für das klassentemplate "test" spezialisierungen gemacht werden müssten oder könnte man ein hier eine klassentemplate statt des funktionstemplates erstellen, welches dann spezialisiert werden kann?



  • Ok habe ne lösung gefunden, welche im grunde das gleiche design beibehält:

    statt des funktions templates verwende ich nun ein funktions objekt template

    #include <iostream>
    #include <vector>
    
    class test
    {
    public:
        template <typename T>
        void print(T& value);
    
        void printRaw(void* data)
        {
            std::cout<<"data: "<<data<<"\n";
        }
    };
    
    namespace dummy
    {
        template<typename T>
        struct printer
        {
            static_assert(sizeof(T) == 0, "unimplemented");
    
            void operator()(test& tt, T& value)
            {
    
            }
        };
    }
    
    template <typename T>
    void test::print(T& value)
    {
        dummy::printer<T>()(*this, value);
    }
    
    namespace dummy
    {
        template<>
        struct printer<int>
        {
        public:
            void operator()(test& tt, int& value)
            {
                std::cout<<"int printer ()\n";
            }
        };
    
        template<>
        struct printer<size_t>
        {
        public:
            void operator()(test& tt, size_t& value)
            {
                std::cout<<"size_t printer ()\n";
            }
        };
    
        template<typename T>
        struct printer< std::vector<T> >
        {
            void operator()(test& tt, std::vector<T>& value)
            {
                std::cout<<"vector<T> printer ()\n";
                size_t size = value.size();
                tt.print(size);
            }
        };
    }
    
    int main()
    {
        test testInst;
    
        int t = 100;
        testInst.print(t);
    
        std::vector<float> ttt;
        testInst.print(ttt);
    
        return 0;
    }
    

Anmelden zum Antworten