JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=a73e544dfbf2ac29b42ce86e95d9e82cMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

[template c++] mehrdeutigkeit ausschließen (?)

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 06.04.2007, 00:18    Titel: [template c++] mehrdeutigkeit ausschließen (?) Antworten mit Zitat

Hi,

ich habe ein leicht verzwicktes Problem mit templates, wozu mir dummerweise gerade die Lösung nicht einfällt; wäre sehr nett wenn mir einer auf die Sprünge helfen kann (gelegenheit zu zeigen, wer auch so angetan ist von den Template-Wundern, wie auch Kampfhund hier ein paar gezeigt hat Cool ):

Stark vereinfacht an einem kleinen Beispiel sieht das so aus (erläuterungen zu dem Code schreib ich drunter):
CPP:
struct Foo1
{
   template<typename T> friend T operator<< ( T t, Foo1 f1 )
   {
      return t;
   }
};

struct Foo2
{
   template<typename T> T operator<< ( T t )
   {
      return t;
   }
};

Also: ich habe wie man sieht zwei Klassen (hier der Einfachheit halber structs). Die Funktionsrümpfe in beiden sind in dem Bsp. hier zwar sinnlos, aber ich hab versucht es so klein wie möglich zu halten. In Foo1 ist ein globaler operator<< definiert, als friend da er in meiner realen Klasse als Ausgabeoperator für streams gilt und private-data-access haben muss. In Foo2 ist ein operator<< als Member deklariert, der in der realen Klasse ein ausgabe-operator von einem Stream ist: das sieht dann so aus, dass Foo2 mein stream ist und Foo1 ein Objekt das auf dem Stream ausgegeben wird, sprich:
CPP:
Foo1 f1;
Foo2 f2;
// ...
f2 << f1;
Kommen wir zum Kern der Sache:

Ich möchte, dass hier der globale operator<< (T, Foo1) aufgerufen wird mit T = Foo2; und nicht der aus Foo2, also nicht Foo2::operator<< (Foo1) mit T = Foo1. Ich möchte also explizit ausschließen, dass der T von Foo2::operator<< den Typ Foo1 annehmen kann.

Das enable_if-Idiom (eine abgeschwächte Art davon) hab ich schon versucht, nur leider kontrolliert der Compiler (der bei msvc++05 express) diese Sache erst nach der Mehrdeutigkeit. Mein Ansatz dabei war folgender, falls das hilfreich sein könnte:
CPP:
template<typename T> struct enable_type
      {      typedef int tt;      };
template<> struct enable_type<Foo1>
      {      typedef void tt;      };

// und dann in dem operator, für den Foo1 ausgeschlossen werden soll:
struct Foo2
{
   template<typename T> T operator<< ( T t )
   {
                enable_type<T>::tt _Foo1_as_T_not_allowed = 0;
      return t;
   }
};
Für T = Foo1 würde da dann nämlich bekanntlicherweisen
CPP:
void _Foo1_as_T_not_allowed = 0;
stehen, was den Fehler erzeugen würde...

So, ziemlich viel, aber ich hoffe ich konnte mein Problem hinreichend gut beschreiben. Wäre sehr nett, wenn einer, der Ahnung von diesen template-geschichten hat, mir dabei helfen könnte. Ich brauch ja im Endeffekt nur etwas in dem 2. op., dass dem Compiler sagt: "T kann hier nicht mit Foo1 instanziert werden" Confused Confused

Gruß DXer, und vielen Dank im Voraus!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
David
Super JLI'ler


Alter: 39
Anmeldedatum: 13.10.2005
Beiträge: 315

Medaillen: Keine

BeitragVerfasst am: 06.04.2007, 01:23    Titel: Antworten mit Zitat

Der Operator<< wird allerdings zwangsläufig so implementiert:

CPP:
struct Foo1
{
   template< typename T >
   friend Foo1& operator<<( Foo1& stream, T& obj )
   {
      return stream;
   }
};


Ansonsten sind Späße wie: x << y << z << foo << bar nich möglich.
Insofern erübrigt sich die Frage egtl! Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 06.04.2007, 12:49    Titel: Antworten mit Zitat

nein, Foo1 ist nicht der Stream sondern ein object. Foo2 ist der stream. das is ja gerade der Unterschied der beiden: In dem globalen operator in Foo1 soll der Streamtyp T der left-type sein, und Foo1 der right-type, sodass dieser globale Operator in allen folgenden Fällen aufgerufen wird:
CPP:
// mehrere streams:
std::ofstream os;
std::wofstream ws;
std::wostringstream wss;
std::stringstream ss;
//...
Foo1 f;
// ...
os << f;       // aufgelöst zu: ::operator<< <std::ofstream> (os, f);
ws << f;      // aufgelöst zu: ::operator<< <std::wofstream> (ws, f);
wss << f;     // aufgelöst zu: ::operator<< <std::wostringstream> (wss, f);
ss << f;       // aufgelöst zu: ::operator<< <std::stringstream> (ss, f);

Das ist praktisch eine weitere Überladung der globalend std::operatoren folgenden Ursprungs (also l = stream, r = object)
CPP:
template<class _Traits> inline
   basic_ostream<char, _Traits>& __CLRCALL_OR_CDECL operator<<(
      basic_ostream<char, _Traits>& _Ostr, char _Ch)


Im Vergleich mit dem operator von Foo2 hingegen sehen die beiden mehrdeutigen Aufrufe so aus:
CPP:
Foo1 obj;
Foo2 stream;
//...
stream << obj;
// mögliche Aufrufe (mehrdeutigkeiten):
//    1.
::operator<< <Foo2> (stream, obj);
//    2.
stream.operator<< <Foo1> (obj);

ich möchte dem Compiler dabei irgendwie klar machen, dass es nur die 1. möglichkeit geben kann. Es soll für ihn also keine Möglichkeit geben, Foo2::operator<< mit Foo1 instanzieren zu können, sprich: Foo1 soll nicht in der Liste der möglichen template-Parameter von Foo2::operator<< stehen, sodass nur der Aufruf durch den globalen operator infrage käme.

Wenn es dabei keine Möglichkeit gibt, werde ich wohl oder übel den template-operator in Foo1 zum normalen operator machen müssen und ihn dann für alle möglichen stream objekte überladen, also auch für Foo2.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
David
Super JLI'ler


Alter: 39
Anmeldedatum: 13.10.2005
Beiträge: 315

Medaillen: Keine

BeitragVerfasst am: 06.04.2007, 16:03    Titel: Antworten mit Zitat

Na viel Spaß! In deinem Fall ist der Operator << eben doppelt implementiert. Nimm eine Version raus und gut is. Der Ansatz mit dem enable_if Idiom kann nicht funktionieren, da das nichts daran ändert das der Operator zweimal implementiert wurde.

Wie du dem Compiler klar machst welche Funktion aufgerufen werden soll hast du ja bereits selbst gesagt:

CPP:
operator<< < Foo2 >( f2, f1 );
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 06.04.2007, 16:44    Titel: Antworten mit Zitat

nun gut, ich habe das jetzt folgendermaßen gemacht:
CPP:
struct Foo2;

struct Foo1
{
     inline friend Foo2& operator<< (Foo2& stream, Foo1& obj)
     {
          return obj.writeToStream(stream);
     }
     inline friend std::ostream& operator<< (std::ostream& stream, Foo1& obj)
     {
          return obj.writeToStream(stream);
     }
     inline friend std::ofstream& operator<< (std::ofstream& stream, Foo1& obj)
     {
          return obj.writeToStream(stream);
     }
     inline friend std::ostringstream& operator<< (std::ostringstream& stream, Foo1& obj)
     {
          return obj.writeToStream(stream);
     }
     // usw. für andere streams

private:
     template<typename T_Stream>  T_Stream& writeToStream(T_Stream& str)
     {
          // code zur speziellen ausgabe auf stream...

          return str;
     }   
};


Der Hintergrund dafür ist, dass Foo2::operator<< ein (intern formatierter) standard-ausgabeoperator für Foo2-streams darstellt. Für Foo1 möchte ich aber eine ganz spezielle Ausgabe haben, da es ja 1. kein integrierter Typ ist und 2. eigene Variablen hat, die ausgegeben werden sollen. Foo2::operator<< kennt von Natur aus keine Foo1-Objekte und wüsste daher auch nicht, wie es mit solchen umgehen müsste. Ein
CPP:
Foo2::operator<< <Foo1> (f1);
verursacht somit auch explizit errors ala "... kann nicht in int konvertiert werden" o.Ä. Trotzdem hat der Compiler es als Mehrdeutigkeit angesehen, obwohl klar war, dass es nur die eine Möglichkeit (nämlich die über den globalen Operator) geben kann.

Trotzdem vielen Dank für deine Geduld und Hilfe, david! Wink Very Happy

Gruß DXer

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
xardias
JLI Master


Alter: 38
Anmeldedatum: 28.12.2003
Beiträge: 804
Wohnort: Palo Alto, CA
Medaillen: Keine

BeitragVerfasst am: 22.05.2007, 13:35    Titel: Antworten mit Zitat

afaik muss man beim aufrufen von templateisierten memberfunktionen eine spezielle syntax verwenden welche von kaum einem compiler unterstützt wird.

ich hab den stroustrup nicht zur hand aber um
Code:
class A
{
template<class > test(T blub){...}
}

aufzurufen muss man afaik folgende syntax verwenden:
Code:
A a;
a.template<int> test(test);

wie das dann bei operatoren funktionieren soll.. keine ahnung ob das überhaupt möglich ist.. zumal die syntax von kaum einem compiler unterstützt wird und somit (ich spreche für gcc) das ganze überhaupt nicht möglich ist.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
David
Super JLI'ler


Alter: 39
Anmeldedatum: 13.10.2005
Beiträge: 315

Medaillen: Keine

BeitragVerfasst am: 22.05.2007, 16:17    Titel: Antworten mit Zitat

Wie wärs mit:

CPP:
struct foo
{
   template< typename T > void bla( const T& )
   {}

   template< typename T > foo& operator+=( const T& )
   {
      return *this;
   }
};

int main()
{
   foo x;
   
   x.bla( 100 ); // Erkennt automatisch int für den Templateparameter
   x.bla< float >( 100 ); // Templateparameter statisch angeben
   x.operator+=< float >( 100.0f ); // Operator += mit statischen Templateparameter

   std::cin.get();
}


Der Aufruf von "Operator" und Methode funktioniert nämlich ganz genau gleich weil du nicht den Operator aufrust sondern die Methode operator+=( const T& ).
Komisch dass das so wenig Leute kapieren. Man übschreibt in C++ niemals irgendeinen Operator sondern immer nur die Methode/Funktion die vom Operator aufgerufen wird.

grüße
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 22.05.2007, 17:45    Titel: Antworten mit Zitat

xardias hat Folgendes geschrieben:

Code:
class A
{
template<class > test(T blub){...}
}

aufzurufen muss man afaik folgende syntax verwenden:
Code:
A a;
a.template<int> test(test);

du hast recht, es gibt diese syntax, und in boost kommt sie sogar unter manchen Vorraussetzungen zum Einsatz, aber es geht auch anders: (und dies wird im Grunde von fast allen Compilern unterstützt):
CPP:
A a;
a.test<int> test(test);
Aber eigtl ist selbst das nicht nötig, da wenn die Funktion einen Parameter des Typs T erwartet und auch bekommt, dann ermittelt der Compiler (und das ist nach ISO C++ Standard vorausgesetzt) den Typ selber, wie auch david schon gezeigt hat:
CPP:
A a;
a.test(test);


BTW: Ohne dich jetz ärgern zu wollen, da ist so ein... naja... inneres Verlangen in mir, das mich zwingt, deine Template-Member-Definition richtig zu stellen, sorry Razz Razz
CPP:
class A
{
     template<class T> T test(T blub){...} // Template-typname, Rückgabewert
}; // <-


Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
xardias
JLI Master


Alter: 38
Anmeldedatum: 28.12.2003
Beiträge: 804
Wohnort: Palo Alto, CA
Medaillen: Keine

BeitragVerfasst am: 23.05.2007, 15:38    Titel: Antworten mit Zitat

sorry, saß im info praktikum war deprimiert wegen der beknackten aufgaben und mir war langweilig. da passieren so fehler Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum