Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Template-bastelei

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ] [ 3 ] [ 4 ]
000
14.08.2003, 11:10 Uhr
0xdeadbeef
Gott
(Operator)


Moin,

Es geht um folgendes: Ich hab mir eine template zusammengeschustert, die von ihrem Parameter ableitet. Schema:

C++:
template <class _TP> class MyTemplate : public _TP {
//...
};


Des weiteren habe ich eine Klasse, die die Template verwendet, unabhängig von der Basisklasse. Schema:

C++:
class MyClass {
//...
  template <class _TP> void use_template(MyTemplate<_TP> &mt) {
    //Zeuch machen.
  }
};


Soweit, so gut, das läuft auch. jetzt will ich dem Parameter der template-Funktion MyClass::use_template einen Default-Wert zuweisen, das den this-Pointer zur Initialisierung verwendet. Also:

C++:
  template <class _TP> void use_template(MyTemplate<_TP> &mt = MyTemplate<MyBaseClass>(this)) {
    //...
  }


Und da schmeißt mit der Compiler (VC++ 6.0 - ich weiß, ich weiß. Hätt auch gern nen gcc) folgendes raus:

Code:
error C2355: 'this' : can only be referenced inside non-static member functions


Woran liegts, krieg ich das hin, und wenn ja, wie? Ansonsten muss ich mir mit so nem unschönen Bastel-Move a la

C++:
//.h
void use_template();

//.cpp
void MyClass::use_template() { use_template(MyTemplate<MyBaseClass>(this)); }


helfen. Das geht auch, aber ich will das eigentlich nicht.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
14.08.2003, 11:31 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
0xdeadbeef postete

...

C++:
  template <class _TP> void use_template(MyTemplate<_TP> &mt = MyTemplate<MyBaseClass>(this)) {
    //...
  }


Und da schmeißt mit der Compiler (VC++ 6.0 - ich weiß, ich weiß. Hätt auch gern nen gcc) folgendes raus:

Code:
error C2355: 'this' : can only be referenced inside non-static member functions


Woran liegts, krieg ich das hin, und wenn ja, wie?



Hat weder was mit dem VC noch Templates zu tun:

Der Fehler steht ja schon da: Du verwendest this nicht in einem Initialisierer oder in einem Methodenbody, sondern bei der Vergabe eines Defaultparameters. Daß das nicht geht, liegt auf der Hand:

C++:
struct X
{
    void f(X* x = this); // Geht natürlich nicht, aber wir nehmen es mal an...
};

int main()
{
   X x;
   x.f(); // Was sollte nun this (der defaultparameter) sein???
}


Ein default Parameter muß also kontextunabh. zu gebrauchen sein. Das ist bei this nicht der Fall.
Wie man es alternativ lösen kann hängt nicht unerheblich davon ab, was du genau vorhast.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
14.08.2003, 11:36 Uhr
0xdeadbeef
Gott
(Operator)


Die Methode f(X*) ist doch nicht statisch. Und sowas wie

C++:
struct X;

X* bla;

struct X {
  void f(X *p = bla) { }
};

int main() {
  X y;
  bla = &y;
  y.f();
}


geht ja auch. Von daher hätte ich erwartet, dass bei deinem Beispiel &x == this.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 14.08.2003 um 11:39 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
14.08.2003, 11:52 Uhr
virtual
Sexiest Bit alive
(Operator)


bla ist aber eine globale oder statische Variable. die ist immer da. this eben nicht.
Du kannst Temp. Objekte, reintun:

C++:
void f(std::string x = "beefy");


Du kannst Ergebnisse von statischen Methoden oder funktionen reintun:

C++:
std::string g()
{
    return "beefy";
}
void f(std::string x = g());


Du kannst Variablen rein tun:

C++:
std::string d = "beefy";
void f(std::string x = d);


Und so weiter.
All diese Sachen sind unabh. vom Kontext immer auswertbar.


Bearbeitung:

Die Frage ist weniger, ob die Methode, der du Defaultargumente verpasst, statisch ist. Die Frage ist vielmehr, in welchen Situationen der Compiler was mit den Defaultargumenten anfangen kann. Und da gibt es eine ganz einfache Regel: er muß immer was mit anfangen können.


--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 14.08.2003 um 11:56 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
14.08.2003, 12:00 Uhr
0xdeadbeef
Gott
(Operator)


Sieht so aus, als hättest du damit recht, aber wirklich Sinn macht das nicht. Der Default-Parameter muss ja nur in Situationen auswertbar sein, in denen es überhaupt möglich ist, dass er ausgewertet wird - genau dann, wenn die Methode aufgerufen werden kann. Und weil es keine statische Methode ist, gibt es dann auch einen this-Pointer.

Scheinbar hat Soustroup da die Linie "Wenn man dazwischen entscheiden muss, die Sprache oder den Compiler schwerer zu machen, nehme ich die zweite Option" nicht wirklich durchgezogen...
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
14.08.2003, 12:59 Uhr
virtual
Sexiest Bit alive
(Operator)


Ich weiß nicht recht:
Die Namen von Defaultargumenten werden eben bereits zum Zeitpunkt der Deklaration der Funktion gebunden. Bei sowas wie Du dir vorstellst, wären solche Codestücke (die man konsequenterweise auch erlauben müsste) ja der reinste Graus:

C++:
/* header.h */
#ifndef HEADER_H
#define HEADER_H

extern const char* ptr;
const char* g(const char* p = ptr);

#endif



C++:
/* impl.C */
#include "header.h"

const char* ptr = "globaler_ptr";

const char* g(const char* p)
{
    return p;
}



C++:
/* main.C */
#include <iostream>
#include "header.h"

const char* f()
{
    const char* ptr = "local_ptr";
    return g();
}


int main()
{
std::cout << f() << std::endl;
}



Dann würde nämlich plötzlich - wenn es nach Dir ginge - "local_ptr" ausgegeben. Und das nur, weil du auf Die Idee gekommen bist, in f eine Variable namens ptr einzuführen.

Bearbeitung:
Um es ganz duetlich zu sagen: Du hast ptr natürlich nur Zufällig so gewählt, weil Du damit eigentlich nicht so sehr den Rückgabewert von g() beinflussen wolltest, sonderen weil es eben eine lokale Variable ist. Würde das Konzept der Namensbindung von Defaultargumenten zum Deklarationszeitpunkt aufgehoben, müsstest Du also alle Header durchforsten, damit du sicherstellst, daß durch wie wahl der Namen der variablen kein ungebetener Nebeneffekt auftrifft

Klar, jetzt könntest Du das Gegenargument bringen: Dann sollte es C++ eine Ausnahmeregelung geben, daß diese Bindung der Namen nicht für this gilt. Mir ist aber eine klare Regel lieber, als eine Regel mit Ausnahmen. Von denen gibt es nämlich genug und machen die Sprache nicht grade leichter zu verstehen. Deshalb glaube ich, daß diese "Einschränkung", die du siehst, eher zur Vereinfachung der Sprache beiträgt, als sie "schwerer" zu machen.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 14.08.2003 um 13:09 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
14.08.2003, 13:37 Uhr
0xdeadbeef
Gott
(Operator)


Der Code, den du gepostet hast, kompiliert und läuft ohne Probleme. Ausgabe:

Code:
global_ptr


Und das macht auch Sinn, wenn du dir ankuckst, was Default-Werte eigentlich sind. Code wie

C++:
//f.h
void f(char = 'A');

//f.cpp
#include "f.h"
#include <iostream>
void f(char c) { std::cout << c; }

//main.cpp
#include f.h
int main() { f(); }


ist gleichbedeutend mit

C++:
//f.h
//Deklaration von f(char c = 'A') aufgespalten in:
void f();
void f(char c);

//f.cpp
#include "f.h"
#include <iostream>

//Implementation von f(char c = 'A') aufgespalten in:
void f() { f('A'); }
void f(char c) { std::cout << c; }

//main.cpp
#include "f.h"

//Weder Implementation noch Deklaration zu sehen - keine Veränderung.
int main() { f(); }


Ich finde, das macht durchaus Sinn.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
14.08.2003, 13:41 Uhr
0xdeadbeef
Gott
(Operator)


Oder, um es am Beispiel this zu zeigen:

C++:
//x.h
struct X {
    void f(X* = this);
};

//x.cpp
void X::f(X*) { }

//main.cpp
int main() { }


wäre

C++:
//x.h
struct X {
    //aufgespalten
    void f();
    void f(X*);
}

//x.cpp
#include "x.h"
//aufgespalten:
void X::f() { f(this); }
void X::f(X* px) { }

//main.cpp
#include "x.h"
//nichts zu sehen.
int main() { }


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
14.08.2003, 14:18 Uhr
virtual
Sexiest Bit alive
(Operator)


Klar compiliert der Code. Ich habe auch nie daran gezweifelt, daß global_ptr ausgegeben wird. Worauf ich hinaus wollte war folgender Umstand:

Wie erwähnt geschieht die Bindung der Defaultargumente bei der Deklaration der Funktion mit dem Defaultargument (in meinem Beispiel Funktion g).
Wenn man etwas machen wollte, damit this auch als Defaultargument durchginge, dann müsste man diese Regel entweder aufheben (mit dem in meinem Post aufgezeigten unangenehmen Nebeneffekten) oder aber eine Sonderregelung für this finden. Beides meiner führt meiner Meinung nach dazu, daß die Sprache nicht leichter, sondern schwerer wird.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
14.08.2003, 14:38 Uhr
virtual
Sexiest Bit alive
(Operator)


Ach ja, noch was:



Zitat:
0xdeadbeef postete
Oder, um es am Beispiel this zu zeigen:

C++:
//x.h
struct X {
    void f(X* = this);
};




Okay, laß mich das mal anwenden/erweitern:


C++:
struct X {
    void f(X* = this);
    void g(X* x);
};

...

X::g(X* x)
{
     x->f(); // Wir reden über diesen Aufruf!
}


Was soll denn nun an f() fübergeben werden? - Folgt man der Implementation

C++:
void X::f() { f(this); }


Die Du vorgschlag hast, dann wäre das eigentlich nichts anderes als der Aufruf

C++:
x->f(x);


Wenn ich aber davon ausgehe, daß this in X::g eben nicht x ist, sondern auf eine andere Instanz von X zeigt, dann kann ich nun komplett keinen Sinn mehr in dem Defaultparameter erkennen, weil es einfach nicht durchschaubar ist.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 14.08.2003 um 14:40 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ] [ 3 ] [ 4 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: