Template-Methode (Operator) mit Template spezialisieren



  • Folgende Situation:

    class ByteStreamWriter
    {
    public:
    
    	template <class T>
    	ByteStreamWriter &operator << (const T &value)
    	{
    		//...
    		return *this;
    	}
    };
    
    //jetzt würde ich gerne festlegen, wie vector2d gehandhabt wird, aber für ein beliebiges T
    template <class T>
    Stream &operator << (ByteStreamWriter &bsw, const vector2d<T> &value)
    {
    	//...
    	return bsw;
    }
    
    //...
    
    ByteStreamWriter bsw;
    bsw << vector2d<int>(); //Fehler
    

    Dieses Problem gibts bei MinGW, jedoch nicht bei VC++:
    `

    C:...\header.h|173|error: ambiguous overload for 'operator<<' in '... (irgendeine Funktion eben)'|

    `

    Was kann man da machen?


  • Mod

    TyRoXx schrieb:

    Was kann man da machen?

    Was willst du denn? Spezialisierung liegt hier nicht vor und ohne den fehlerverursachenden Ausdruck, die verwendeten Typen und die vollständige Fehlermeldung kann man nur raten.



  • camper schrieb:

    Spezialisierung liegt hier nicht vor

    Ja eben, das ist das Problem. Das habe ich vielleicht nicht deutlich gesagt.

    camper schrieb:

    ohne den fehlerverursachenden Ausdruck, die verwendeten Typen und die vollständige Fehlermeldung kann man nur raten.

    Tut mir Leid, ich war mit den Gedanken nicht ganz bei der Sache.

    `

    C:....\filedb.h|173|error: ambiguous overload for 'operator<<' in 'bsw << ((const stx::fdb::GetSetField<stx::vector2dstx::uint32 >*)this)->stx::fdb::GetSetField<stx::vector2dstx::uint32 >::m_value'|

    C:....\bytestreamwriter.h|108|note: candidates are: stx::ByteStreamWriter& stx::ByteStreamWriter::operator<<(const T&) [with T = stx::vector2dstx::uint32]|

    C:....\vector2d.h|237|note: stx::ByteStreamWriter& stx::operator<<(stx::ByteStreamWriter&, const stx::vector2d<T>&) [with T = stx::uint32]|

    C:....\filedb.h||In member function `void stx::fdb::GetSetField<T>::serialize(stx::ByteStreamWriter&) const [with T = stx::vector2dstx::sint32]':|

    `

    Die Meldung bezieht sich auf vector2d<T> , was hier aber keinen Unterschied macht. Bei std::basic_string ließ sich das Problem "lösen", indem man für std::string und wstring einzeln spezialisiert hat. Das soll natürlich auch nicht so sein.


  • Mod

    Verzichte einfach darauf, Operatoren als Member zu definieren. Dafür gibt es ohnehin oft genug keinen Grund. Existieren beide Operatoren als freie Funktionen, ist die Überladung wieder eindeutig, da das eine Template spezieller als das andere ist.



  • Danke, das hat geholfen, auch wenn ich nicht verstehe, warum. Weshalb ist ist die Überladung der Methode nicht so speziell?


  • Mod


  • Mod

    TyRoXx schrieb:

    Danke, das hat geholfen, auch wenn ich nicht verstehe, warum. Weshalb ist ist die Überladung der Methode nicht so speziell?

    Weil die Parameterlisten nicht in Übereinstimmung zu bringen sind.

    14.5.5.2 schrieb:

    ...
    2 Given two overloaded function templates, whether one is more specialized than another can be determined by transforming each template in turn and using argument deduction (14.8.2) to compare it to the other.
    3 The transformation used is:
    — For each type template parameter, synthesize a unique type and substitute that for each occurrence of that parameter in the function parameter list, or for a template conversion function, in the return type.
    — For each non-type template parameter, synthesize a unique value of the appropriate type and substitute that for each occurrence of that parameter in the function parameter list, or for a template conversion function, in the return type.
    — For each template template parameter, synthesize a unique class template and substitute that for each occurrence of that parameter in the function parameter list, or for a template conversion function, in the return type.
    4 Using the transformed function parameter list, perform argument deduction against the other function template. The transformed template is at least as specialized as the other if, and only if, the deduction succeeds and the deduced parameter types are an exact match (so the deduction does not rely on implicit conversions).

    Das implizite Objektargument eines Memberfunktionsaufrufes ist aber nicht Teil der Argumentliste und nimmt nicht an der Templateargumentdeduktion teil. Folglich stimmt die Zahl der Parameter nicht überein und eine partielle Ordnung zwischen memberfunktion und freier Funktion kann nicht etabliert werden.

    Bei normalen benannten Funktion besteht dieses Problem nicht in gleicher Weise, da kein Kontext existiert, in dem sowohl Memberfunktionen als auch eine nicht-Member Teil des Kandidatensets eines überladenen Funktionsaufrufes sind (ADL findet nicht statt, wenn beim unqualifizierten Lookup eine Memberfunktion gefunden wird, ADL kann keine Memberfunktionen finden, und unqualifiziertes Lookup kann nicht gleichzeitig Member- und nicht-Memberfunktionen finden).
    Partielle Ordnung zwischen nicht-statischen und statsischen Memberfunktionen ist möglich, allerdings besitzen auch nicht-statische Memberfunktionen einen impliziten Objektparameter (13.3.1/4), das stellt also nicht unbedingt eine Besonderheit dar.

    Es dürfte genügen, sich zu merken, dass keine partielle Ordnung zwischen überladenen Operatortemplates existiert, die einerseits als nicht-member- und anderseits als Membertemplates überladen wurden.

    #include <iostream>
    
    struct bar {};
    
    template <typename T> static void f(T*, bar) { std::cout << "::f\n"; }
    template <typename T> static void g(T, bar) { std::cout << "::g\n"; }
    
    struct foo
    {
        template <typename T> static void f(T*, bar) { std::cout << "static f\n"; }
        template <typename T> static void g(T, bar) { std::cout << "static g\n"; }
        template <typename T> void f(T, bar) { std::cout << "nonstatic f\n"; }
        template <typename T> void g(T*, bar) { std::cout << "nonstatic g\n"; }
        void fun()
        {
            bar b;
            f("f",b);
            g("g",b);
        }
    };
    
    int main()
    {
        foo f;
        f.fun();
    }
    

    Ausgabe:

    static f
    nonstatic g
    

    Die freien Funktionen werden gar nicht erst betrachtet, weil kein ADL stattfindet.


Anmelden zum Antworten