partielle Template Spezialisierung multi-dimension C-arrays

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

partielle Template Spezialisierung multi-dimension C-arrays

Beitrag von kaiserludi »

Moin. Ich habe eine Templateklasse, die als Datencontainer für bestimmte Typen gilt. Für die verschiedenen unterstützten Datentypen gibt es Spezialisierungen des Templates für bestimmte Methoden, für die es bewusst keine Generalisierte Version gibt.
Foo<int>(aInt) funzt also, Foo<unsupportedType>(unsupportedType), Foo<unsupportedType>(int), Foo<int>(unsupportedType) hingegen werfen alle Compilerfehler.
Dies garantiert Typsicherheit in der API unserer Library. Was unterliegende Schichten nicht verarbeiten können, lässt die API gar nicht erst durch, weil die Container, die sie erwartet, es nicht aufnehmen können.

Nun wollen wir Support für multidimensionale C-Arrays adden und wenn ich die in Form von void* in der API erwarte, dann war es das natürlich, mit der typsicheren API.
Eigene Spezialisierungen oder Überladungen für alle Dimensionen sind natürlich nicht möglich, denn es können es können ja theoretisch n-dimensionale Arrays mit n gegen unendlich übergeben werden (in der Praxis setzt natürlich der Speicherbereich der Variable, die die Anzahl der Dimensionen speichert, eine natürliche Grenze).
Es gibt ja nun partielle Spezialisierungen für Templates, die klassischerweise für Pointer verwendet werden, also <Etype> als generelle Implementation des Templates, <Etype*> als Spezialisierung für alle Arten von eindimensionalen Pointern auf egal welchen Typ. Was mir nun vorschwebt, wäre eine partielle Spezialisierung für C-Arrays jeglicher Dimension eines bestimmten Types.
int*, int**, int***, int****, usw. würden also alle akzeptiert werden, unsupportedType* hingegen nicht.

Ist sowas möglich? Wenn ja, wie sähe die Syntax aus?
Habe dazu leider weder im Web noch im Stroustrup was gefunden.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

Rekursion, wie immer bei Templates?

Code: Alles auswählen

template <typename CType> struct TCContainerTypeFor { typedef Foo<CType> type; };
template <typename CElementType> struct TCContainerTypeFor<CElementType *> { typedef Foo<TCContainerTypeFor<CElementType>::type> type; };

static_assert(typeid(TCContainerTypeFor<int>::type) == typeid(Foo<int>), "!");
static_assert(typeid(TCContainerTypeFor<int**>::type) == typeid(Foo<Foo<Foo<int>>>), "!!");
Nur hingehackt – nur, falls ich dich richtig verstanden habe – ohne Gewähr. Musst du natürlich noch für die const/volatile-Version überladen und – falls du statische Arrays benutzt – am besten noch eine Version hinzufügen, die die Bereichsgrenzen prüft.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Hmm, ich bin mir nicht ganz sicher, ob du mich nicht verstanden hast oder ich dich nicht, habe mit Templates auch noch nicht so viel Erfahrung, als dass ich mich da als absolut sattelfest sehen würde.

Ich habe folgende Klasse:

Code: Alles auswählen

template <class Etype>
	class ValueObject:public Object
	{
	public:
		/* Summary
		Destructor. */
		~ValueObject(void);

		ValueObject(const ValueObject<Etype>& toCopy);

		ValueObject(const Object* const obj);

		ValueObject(const nByte data);
		ValueObject(const short data);
		ValueObject(const int data);
		ValueObject(const int64 data);
		ValueObject(const bool data);
		ValueObject(const nByte* data, const int size);
		ValueObject(const int* data, const int size);
		ValueObject(const JString& data);
		ValueObject(const JString* data, const int size);
		ValueObject(const JVector<Object>& data);
		ValueObject(const Hashtable& data);
		ValueObject(const float data);
		ValueObject(const double data);
		ValueObject(const int64* data, const int size);
		ValueObject(const bool* data, const int size);
		ValueObject(const float* data, const int size);
		ValueObject(const short* data, const int size);
		ValueObject(const double* data, const int size);

		Etype getDataCopy(void);
		Etype* getDataAddress(void);

	private:
		void convert(const Object* const obj, nByte type);

		ValueObject<Etype>& operator=(const ValueObject<Etype>& notToUse);
	};
Nun hätte ich auch gerne die Möglickeit, neben Aufrufen wie ValueObject<int>(myInt) oder ValueObject<int*>(myIntArray, size) auch solche Calls zu ermöglichen:
ValueObject<int******>(aSixDimensionalIntArray, sizes), wobei sizes ein eindimensionaler array wäre mit so vielen Elementen, wie Parameter 1 an Dimensionen hat.
Calls wie ValueObject<long double**>(aLongDouble) sollen aber weiterhin nicht erlaubt sein.

Natürlich könnte ich das erreichen, in dem ich einfach folgende Überladungen zur Klasse hinzufüge:
ValueObject(const int* data, const int* sizes);
ValueObject(const int** data, const int* sizes);
ValueObject(const int*** data, const int* sizes);
ValueObject(const int**** data, const int* sizes);
ValueObject(const int***** data, const int* sizes);
ValueObject(const int****** data, const int* sizes);
ValueObject(const int******* data, const int* sizes);
ValueObject(const int******** data, const int* sizes);
ValueObject(const int********* data, const int* sizes);
ValueObject(const int********** data, const int* sizes);
usw.
aber dann steht man immer vor dem Dilemma, dass man entweder wahnsinnig viel Code hat oder es doch irgendwem noch eine Dimension zu wenig ist und der Spaß würde sich natürlich für alle Datentypen wiederholen, also brauche ich besseren Approach.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:wobei sizes ein eindimensionaler array wäre mit so vielen Elementen, wie Parameter 1 an Dimensionen hat.
Du kannst herausfinden, wie viele Dimensionen das Array hat und falls es statisch ist, kannst du auch die Länge jeder Dimension bestimmen. Aber du kannst dir daraus nicht einen Parameter füllen lassen – diese Information steht dir nur in statischer Form zur Verfügung und du kannst sie nur rekursiv verarbeiten.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Es geht mir mehr darum, wie ich dem Aufrufer erlauben kann, n-dimensionale int--arrays zu übergeben, ohne ihm zu erlauben, arrays beliebigen typs zu übergeben.
Was den die Längen angeht, komme ich bei c-arrays eh nicht drum herum, die durch den Aufrufer übergeben zu lassen.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

Achso. Jaa, ist ja ganz einfach:

Code: Alles auswählen

template <typename CType> struct TCConfirmAllowed;
template <> struct TCConfirmAllowed<int> { typedef int type; };
template <> struct TCConfirmAllowed<bool> { typedef bool type; };
// … usw. Wirst du ja so ähnlich schon für alle erlaubten Typen spezialisiert haben
template <typename CType> struct TCConfirmAllowed<CType *> { typedef typename TCConfirmAllowed<CType>::type type; };

…
class ValueObject {´
    …
    template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
Knifflig wird es aber, wenn c/v-Qualifier hineinkommen – der Code oben wird int const * nicht als gültigen Typ erkennen. Damit also auch das akzeptiert würde, musst du erweitern:

Code: Alles auswählen

template <> struct TCConfirmAllowed<int const> { typedef int const type; };
template <> struct TCConfirmAllowed<int volatile> { typedef int volatile type; };
template <> struct TCConfirmAllowed<int const volatile> { typedef int const volatile type; };
Und damit dasselbe nochmal mit Zeigern geht:

Code: Alles auswählen

template <typename CType> struct TCConfirmAllowed<CType * const> { typedef typename TCConfirmAllowed<CType>::type * const type; };
template <typename CType> struct TCConfirmAllowed<CType * volatile> { typedef typename TCConfirmAllowed<CType>::type * volatile type; };
template <typename CType> struct TCConfirmAllowed<CType * const volatile> { typedef typename TCConfirmAllowed<CType>::type * const volatile type; };
Oder alternativ ein Template, das dir die C/V-Qualifier automatisch rausnimmt und wieder anfügt, schreiben.

Noch ein Stolperdraht: Nicht-Template-Funktionen werden immer bevorzugt. Das bedeutet: Würdest du irgendwann mal einen K’tor mit void *-Parameter hinzufügen, würde das Template nie mehr aufgerufen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

So, konnte mich ein paar Tage nicht mit diesem Thema beschäftigen, jetzt bin ich wieder dran und habe gleich die nächste Frage dazu:

Ein Aufruf wie folgt:

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<TCConfirmAllowed<nByte**>>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
schmeißt mir die Fehlermeldung
error C2661: 'ValueObject<Etype>::ValueObject' : no overloaded function takes 3 arguments
obwohl die Klasse nun folgenden Konstruktor deklariert:

Code: Alles auswählen

template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int dimension, const short* sizes);
Da scheine ich syntaktisch noch nicht ganz durch zu blicken.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
BeRsErKeR
Establishment
Beiträge: 689
Registriert: 27.04.2002, 22:01

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von BeRsErKeR »

kaiserludi hat geschrieben:Ein Aufruf wie folgt:

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<TCConfirmAllowed<nByte**>>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
Kann mich irren aber muss das nicht so heißen?

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
Ohne Input kein Output.
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

BeRsErKeR hat geschrieben: Kann mich irren aber muss das nicht so heißen?

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
Habe ich auch ausprobiert, aber führt zur gleichen Fehlermeldung.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

(BeRsErKeR hat recht, afaik kann man außerdem die explizite Angabe des <nByte**>-Template-Parameters weglassen, weil sie der Compiler selber auflösen können müsste.)

Was ist das Problem an der Fehlermeldung? Du übergibst drei Parameter, aber hast keinen Konstruktor definiert, der drei annimmt. In dem Post oben, wo du ValueObject definiert hast, nehmen die Konstruktoren auch nur entweder einen oder zwei Parameter. Das (short*)NULL kommt aus dem Nichts.

Vor das TCConfirmAllowed<nByte**>::type((nByte**)NULL) muss afaik auch noch ein typename, sonst weiß der Compiler nicht, ob es sich nciht vielleicht um einen Funktionsaufruf handelt.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Wenn ich die explizite Angabe des template-Parameters weglasse, dann meckert VS "Use of class template requires template argument list".

Zu den 3 Parametern:
War ein Verständnisproblem, ich dachte, mit der Zeile:
"template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int dimension, const short* sizes);" hätte ich einen Konstruktor deklariert, der 3 Parameter nimmt.

ich habe nun die Klasse um folgende Konstruktoren erweitert:

Code: Alles auswählen

ValueObject(const nByte** data, int dimensions, short* sizes);
ValueObject(const int** data, int dimensions, short* sizes);
ValueObject(const JString** data, int dimensions, short* sizes);
ValueObject(const int64** data, int dimensions, short* sizes);
ValueObject(const bool** data, int dimensions, short* sizes);
ValueObject(const short** data, int dimensions, short* sizes);
ValueObject(const float** data, int dimensions, short* sizes);
ValueObject(const double** data, int dimensions, short* sizes);
Den Aufruf versteht er jetzt auch:

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte**)NULL, 3, (short*)NULL));
aber dort kommt TCConfirmAllowed auch noch nicht zum Einsatz.

Blooß wie würde ich jetzt einen 3-dimensionalen nByte-array übergeben, also nByte*** ?
Bei dem Code

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), EValueObject<nByte***>(TCConfirmAllowed<nByte***>::type((const nByte***)NULL), 3, (short*)NULL));
vermeldet VS "none of the 28 overloads could convert all the argument types while trying to match the argument list '(unsigned char, int, short *)"

und bei

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
heißt es "none of the 28 overloads could convert all the argument types while trying to match the argument list '(const nByte ***, int, short *)"

Lasst euch btw. nicht durch das nByte verwirren, dass ist einfach nur als unsigned char definiert.
Vor das TCConfirmAllowed<nByte**>::type((nByte**)NULL) muss afaik auch noch ein typename, sonst weiß der Compiler nicht, ob es sich nciht vielleicht um einen Funktionsaufruf handelt.
wie sähe das denn syntaktisch im Code aus?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:ich habe nun die Klasse um folgende Konstruktoren erweitert:

Code: Alles auswählen

ValueObject(const nByte** data, int dimensions, short* sizes);
ValueObject(const int** data, int dimensions, short* sizes);
ValueObject(const JString** data, int dimensions, short* sizes);
ValueObject(const int64** data, int dimensions, short* sizes);
ValueObject(const bool** data, int dimensions, short* sizes);
ValueObject(const short** data, int dimensions, short* sizes);
ValueObject(const float** data, int dimensions, short* sizes);
ValueObject(const double** data, int dimensions, short* sizes);
WT… war es nicht gerade dein Ziel, sowas – also eine Version für jede mögliche Dimension – genau nicht schreiben zu müssen?
kaiserludi hat geschrieben:Blooß wie würde ich jetzt einen 3-dimensionalen nByte-array übergeben, also nByte*** ?
Bei dem Code

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), EValueObject<nByte***>(TCConfirmAllowed<nByte***>::type((const nByte***)NULL), 3, (short*)NULL));
vermeldet VS "none of the 28 overloads could convert all the argument types while trying to match the argument list '(unsigned char, int, short *)"
und bei

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
heißt es "none of the 28 overloads could convert all the argument types while trying to match the argument list '(const nByte ***, int, short *)"
Krishty hat geschrieben:

Code: Alles auswählen

class ValueObject {´
    …
    template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
In diesem Konstruktor kannst du auf den Array-Typ per CType zugreifen, auf die Array-Daten per data. Deinen Dimensionsparameter musst du natürlich noch hinzufügen, aber ich würde ihn besser automatisch durch das Template bestimmen lassen. Ebenso würde ich den originalen Datentyp (also das int oder nByte vor den ***) vom Template bestimmen lassen, das dürfte alles nochmal einfacher machen.
kaiserludi hat geschrieben:
Vor das TCConfirmAllowed<nByte**>::type((nByte**)NULL) muss afaik auch noch ein typename, sonst weiß der Compiler nicht, ob es sich nciht vielleicht um einen Funktionsaufruf handelt.
wie sähe das denn syntaktisch im Code aus?
Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)

Btw – bei 28 Konstruktoren hoffe ich, dass du niemals mehr was an der Klasse ändern müssen wirst.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Krishty hat geschrieben:
kaiserludi hat geschrieben:ich habe nun die Klasse um folgende Konstruktoren erweitert:

Code: Alles auswählen

ValueObject(const nByte** data, int dimensions, short* sizes);
ValueObject(const int** data, int dimensions, short* sizes);
ValueObject(const JString** data, int dimensions, short* sizes);
ValueObject(const int64** data, int dimensions, short* sizes);
ValueObject(const bool** data, int dimensions, short* sizes);
ValueObject(const short** data, int dimensions, short* sizes);
ValueObject(const float** data, int dimensions, short* sizes);
ValueObject(const double** data, int dimensions, short* sizes);
WT… war es nicht gerade dein Ziel, sowas – also eine Version für jede mögliche Dimension – genau nicht schreiben zu müssen?
Ja, war es und ist es auch immer noch. Bloß macht es natürlich wenig Sinn, einen size-array als Parameter zu verlangen für 1D-Arrays, da reicht auch ein einfacher short für die size (nicht int, da über Netz nur 2 byte gesendet werden für die size).Daher muss also ein Overload für 2d schon noch sein, aber ab 3d kann ichs mir dann sparen und dennoch kann man auch 1000D-arrays übergeben, wenn jemand das unbedingt will.
Krishty hat geschrieben:
kaiserludi hat geschrieben:Blooß wie würde ich jetzt einen 3-dimensionalen nByte-array übergeben, also nByte*** ?
Bei dem Code

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), EValueObject<nByte***>(TCConfirmAllowed<nByte***>::type((const nByte***)NULL), 3, (short*)NULL));
vermeldet VS "none of the 28 overloads could convert all the argument types while trying to match the argument list '(unsigned char, int, short *)"
und bei

Code: Alles auswählen

ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
heißt es "none of the 28 overloads could convert all the argument types while trying to match the argument list '(const nByte ***, int, short *)"
Krishty hat geschrieben:

Code: Alles auswählen

class ValueObject {´
    …
    template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
In diesem Konstruktor kannst du auf den Array-Typ per CType zugreifen, auf die Array-Daten per data. Deinen Dimensionsparameter musst du natürlich noch hinzufügen, aber ich würde ihn besser automatisch durch das Template bestimmen lassen. Ebenso würde ich den originalen Datentyp (also das int oder nByte vor den ***) vom Template bestimmen lassen, das dürfte alles nochmal einfacher machen.
Typ und Dimensionszahl vom Template bestimmen lassen klingt vielversprechend. Das heißt, das Template kann herausfinden, die Version mit wie vielen * am ersten Parameter sie ist?
Krishty hat geschrieben:
kaiserludi hat geschrieben:
Vor das TCConfirmAllowed<nByte**>::type((nByte**)NULL) muss afaik auch noch ein typename, sonst weiß der Compiler nicht, ob es sich nciht vielleicht um einen Funktionsaufruf handelt.
wie sähe das denn syntaktisch im Code aus?
Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)

Btw – bei 28 Konstruktoren hoffe ich, dass du niemals mehr was an der Klasse ändern müssen wirst.
Ah, ok, das Schlüsselwort "typename", ich hatte verstanden, ich solle z.B. "int" davor schreiben und konnte mir nicht vorstellen, wie das funzen soll, aber mit "typename" macht es Sinn.
Die Klasse besteht auch fast nur aus Konstruktoren, ansonsten gibts nur noch getDataCopy(), getDataAdress(), eine private Helpermethode und einen Destruktor.

EDIT:
Krishty hat geschrieben:
kaiserludi hat geschrieben:
Vor das TCConfirmAllowed<nByte**>::type((nByte**)NULL) muss afaik auch noch ein typename, sonst weiß der Compiler nicht, ob es sich nciht vielleicht um einen Funktionsaufruf handelt.
wie sähe das denn syntaktisch im Code aus?
Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)
Hmm, da meint VS dann:
error C2899: typename cannot be used outside a template declaration
EDIT2: fixed quotes von Edit1
Zuletzt geändert von kaiserludi am 15.12.2010, 14:43, insgesamt 1-mal geändert.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:Bloß macht es natürlich wenig Sinn, einen size-array als Parameter zu verlangen für 1D-Arrays, da reicht auch ein einfacher short für die size (nicht int, da über Netz nur 2 byte gesendet werden für die size).Daher muss also ein Overload für 2d schon noch sein, aber ab 3d kann ichs mir dann sparen und dennoch kann man auch 1000D-arrays übergeben, wenn jemand das unbedingt will.
Okay. Falls du irgendwann den Überladungsdruck senken willst, sehe ich da aber eine Möglichkeit.
kaiserludi hat geschrieben:Typ und Dimensionszahl vom Template bestimmen lassen klingt vielversprechend. Das heißt, das Template kann herausfinden, die Version mit wie vielen * am ersten Parameter sie ist?
Ja, genau – und, wessen Typs die finalen Array-Elemente sind. Du musst dazu template <> struct TCConfirmAllowed<int> { typedef int type; }; zu

Code: Alles auswählen

template <> struct TCConfirmAllowed<int> {
    typedef int type;
    typedef int scalarType;
    static size_t const dimension = 0; // Was kein Array ist, ist 0-dimensional
};
umschreiben, und die beiden neuen Attribute bei den anderen erlaubten Typen ebenfalls hinzufügen. Die (fehlerhaften, siehe unten!) Zeiger-Versionen template <typename CType> struct TCConfirmAllowed<CType *> { typedef typename TCConfirmAllowed<CType>::type type; }; erweiterst du durch

Code: Alles auswählen

template <typename CType> struct TCConfirmAllowed<CType *> {
    typedef typename TCConfirmAllowed<CType>::type * type; // ACHTUNG siehe unten
    typedef typename TCConfirmAllowed<CType>::scalarType scalarType; // Skalaren Typ von der skalaren Version übernehmen
    static size_t const dimension = TCConfirmAllowed<CType>::dimension + 1; // Eine Dimension mehr als der dereferenzierte Typ
};
Und, dabei fällt mir auf – wichtig: das typedef typename TCConfirmAllowed<CType>::type type; in den oberen Posts war falsch, da muss (wie in dem Code-Stück direkt hier drüber) noch der Zeiger-Deklarator zwischen e>::type und type. Bei den c/v-Versionen muss da das entsprechende * const, * volatile und * const volatile zwischen. Vielleicht funktioniert es deshalb nicht.
(Das sollte dann auch der Punkt sein, an dem ich es mir selber nachbaue statt alles aus dem Kopf zu machen.)
kaiserludi hat geschrieben:Hmm, da meint VS dann:
error C2899: typename cannot be used outside a template declaration
Weil du noch in dem nicht-ge-template-ten Konstruktor bist. Sobald er ein Template ist, muss das typename dahin.

————

Soo, mal selber nachgebaut – eine Funktion, die int, int*, int** usw akzeptiert und die Dimension ausgibt:

Code: Alles auswählen

#include <iostream>

template <
	typename CType
> struct TCConfirmAllowed;

template <> struct TCConfirmAllowed<int> {
    typedef int			type;
    typedef int			scalarType;
    static size_t const	dimension = 0;
};

template <
	typename CType
> struct TCConfirmAllowed<CType *> {
	typedef TCConfirmAllowed<CType> dereferencedInfo;
    typedef typename dereferencedInfo::type *		type;
    typedef typename dereferencedInfo::scalarType	scalarType; // Skalaren Typ von der skalaren Version übernehmen
    static size_t const	dimension = dereferencedInfo::dimension + 1; // Eine Dimension mehr als der dereferenzierte Typ
};

template <
	typename CToBePrinted
> void printDimension(
	CToBePrinted const &
) {
	::std::cout << TCConfirmAllowed<CToBePrinted>::dimension << '\n';
	return;
}

…

int x;
::std::cout << "dimension of x: "; printDimension(x); // "dimension of x: 0"
int** xpp;
::std::cout << "dimension of xpp: "; printDimension(xpp); // "dimension of xpp: 2"
char * cp;
::std::cout << "dimension of cp: "; printDimension(cp); // error C2027: use of undefined type 'TCConfirmAllowed<CType>'; see reference to class template instantiation 'TCConfirmAllowed<CType>' being compiled; see reference to function template instantiation 'void printDimension<char*>(const CToBePrinted &)' being compiled
Per rekursivem Funktionstemplate wäre es dann noch möglich, z.B. das Array automatisch auszudrucken. TCConfirmAllowed<CToBePrinted>::type als Parameter hinzuschreiben konnte der Compiler tatsächlich nicht automatisch auflösen, da hänge ich atm noch dran.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Hmm, ich checke immer noch nicht, wie jetzt der Kontruktoraufruf für z.B. einen 3-dimensionalen Array aussehen würde.

Bei Konstruktionen wie dieser
ValueObject<int***>((const int***)NULL, (const short*)NULL);
heißt es mal wieder "non of the x overloads could convert all argument types"
Kontruktionen mit TCConfirmAllowed im Aufruf scheitern grundsätzlich daran, dass TCConfirmAllowed hier für den Compiler ein undeclared identifier ist.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

So, habe mich nochmal etwas intensiver mit dem Problem auseinander gesetzt:

Code: Alles auswählen

template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
Dieser Konstruktor ist zwar standkonform definierbar, aber überhaupt nicht aufrufbar.
Wenn Funktionsparameter und Templateparamter eines Funktionstemplates nicht übereinstimmen, dann kann der Compiler nicht automatisch am Aufruf ermitteln, für welchen Typ er eine Funktion erstellen musst, weshalb man in diesem Fall explizit beim Aufruf den Templateparameter mit angeben muss.
Leider ist es aber syntaktisch nicht möglich, einen Konstruktor mit Templateparametern aufzurufen, da man ihn gar nicht wirklich selsbt aufruft, sondern dies beim erstellen des Objektes automatisch passiert.

Hier das ganze mal als Testcode, den ihr selbser versuchen könnt, aufzurufen:

Code: Alles auswählen

class Object1:public Object
	{
	public:
		template<typename CType> void test(CType data)
		{
			// can be called without explicit template argument: foo.test(temp);
		}
		template<typename CType> Object1(CType data)
		{
			// can be called without explicit template argument: Object1 foo(temp);
		}
	};

	class Object2:public Object
	{
	public:
		template<typename CType> void test(typename TCConfirmAllowed<CType>::type data)
		{
			// can only be called with explicit template argument: foo.test<int>(temp);
		}
		template<typename CType> Object2(typename TCConfirmAllowed<CType>::type data)
		{
			// CAN NOT BE CALLED AT ALL!
		}
	};
und hier noch die Quelle:
http://learningcppisfun.blogspot.com/20 ... licit.html

hat wer eine alternative Idee zur Lösung des ursprünglichen Problems?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

OK, wenn ich den Kontruktor nicht als Funktionstemplate, sondern als normale Funktione anlege, reicht das in meinem Fall auch, da ich als Templateparameter für TCConfirmAllowed eh immer nur den Templateparameter der Klasse übergeben muss.
Folgendes funktioniert:

Code: Alles auswählen

	template<typename Etype> 
	class VObject:public Object
	{
	public:
		VObject(typename TCConfirmAllowed<Etype>::type data)
		{
		}
	};
Ein 4 dimensionaler int-array wird wie gewünschtvom Compiler akzeptiert:

Code: Alles auswählen

int**** temp;
VObject<int****> bla(temp);
Ein char hingegen wird wie gewünscht nicht ohne expliziten cast akzeptiert

Code: Alles auswählen

char foo;
VObject<char> bla(foo);
ok, nen char als int übergeben, funktioniert natürlich, aber nur, weil der Compiler implizit casten kann, das Objekt irgendeiner beliebigen nicht unterstützen Klasse bekomme ich so wie gewünscht nicht rein:

Code: Alles auswählen

char foo;
VObject<int> bla(foo);
Der Code allerdings verhält sich nicht ganz so, wie man es erwarten würde:

Code: Alles auswählen

char* foobar;
VObject<char*> bla(foobar);
Das führt nämlich zu "fatal error C1001: An internal error has occurred in the compiler." inklusive Windows-Prograamabsturz-Messagebox, dass der automatische Codeoptimierer einen Crash hatte unn dem Hinweis im VS Output, ich sollte meinen Code simplifizieren inder letzen Zeile folgendes Klassentremplates:

Code: Alles auswählen

template<class CType> struct TCConfirmAllowed<CType*>
{
	typedef typename TCConfirmAllowed<CType>::type* type;
	typedef typename TCConfirmAllowed<CType>::scalarType scalarType;
	static size_t const dimension = TCConfirmAllowed<CType>::dimension+1;
};
Visual Studio kommt hier offensichtlich nicht mit dem dimension+1 im Template für CType* klar, wenn kein Template für CType existiert.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Ich habe jetzt neben den ConfirmAllowed-templates für die sklalaren Datentypen auch folgende definiert:

Code: Alles auswählen

	template<class CType> struct ConfirmAllowed<const CType> // const version
	{
		typedef typename ConfirmAllowed<CType>::type type;
		typedef typename ConfirmAllowed<CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType>::dimensions;
		static const nByte typeName = ConfirmAllowed<CType>::typeName;
	};
	template<class CType> struct ConfirmAllowed<CType*> // pointer version
	{
		typedef typename ConfirmAllowed<CType>::type* type;
		typedef typename ConfirmAllowed<CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType>::dimensions+1;
		static const nByte typeName = ConfirmAllowed<CType>::typeName;
	};
	template<class CType> struct ConfirmAllowed<const CType*> // pointer to const version
	{
		typedef typename ConfirmAllowed<CType*>::type type;
		typedef typename ConfirmAllowed<CType*>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType*>::dimensions+1;
		static const nByte typeName = ConfirmAllowed<CType*>::typeName;
	};
Die ersten beiden funzen auch wie gedacht (von dem internal Compiler Error, für den Aufruf der Pointervariante, wenn die skalare Veriante nicht existiert mal abgesehen), letzterer aber nicht.

Folgender Aufruf funktioniert:

Code: Alles auswählen

ValueObject<int*>((int*)NULL, (short*)NULL);
Der hier hingegen

Code: Alles auswählen

ValueObject<const int*>((const int*)NULL, (short*)NULL);
führt zum allseits beliebten "non of the overloads could convert all argument types"-error und dem Compiler Output nach, welche Overloads er in Betracht zieht, sieht er gar keine pointer to const Variante, aber nach wie vor die pointer Variante, die für Etype == const int* eigentlich gar nicht existieren sollte, schließlich existiert für Etype == const int auch die const Variante anstatt der non-const Variante.

Wie muss ich vorgehen, um das ganze für const int* zum Laufen zu bekommen?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

Ich bin, obwohl selber geschrieben, leider viel zu weit da raus – aber sollte ConfirmAllowed<…>::type nicht den Originaltyp wiederspiegeln? In dem Fall muss in der const-Version auch typedef typename ConfirmAllowed<CType>::type const type; stehen. Sonst geht in das Template ein const-qualifizierter Typ rein, aber ein nicht-const-qualifizierter heraus.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Tatsächlich, das hatte ich übersehen, hat auch beim scalaren Const gefehlt, dort aber keine Probleme verursacht, wodruch es mir nicht aufgefallen ist, dann beim const* wurde es dann scheinbar zum Problem.
Korrekt ist der Code also wie folgt:

Code: Alles auswählen

	template<class CType> struct ConfirmAllowed<const CType>
	{
		typedef typename const ConfirmAllowed<CType>::type type;
		typedef typename const ConfirmAllowed<CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType>::dimensions;
		static const nByte typeName = ConfirmAllowed<CType>::typeName;
	};
	template<class CType> struct ConfirmAllowed<CType*>
	{
		typedef typename ConfirmAllowed<CType>::type* type;
		typedef typename ConfirmAllowed<CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType>::dimensions+1;
		static const nByte typeName = ConfirmAllowed<CType>::typeName;
	};
	template<class CType> struct ConfirmAllowed<const CType*>
	{
		typedef typename const ConfirmAllowed<CType>::type* type;
		typedef typename const ConfirmAllowed<CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<CType>::dimensions+1;
		static const nByte typeName = ConfirmAllowed<CType>::typeName;
	};
Man beachte im letzten Block, dass es "typedef typename const ConfirmAllowed<CType>::type* type;" heißen muss, um für einen const* zu funktionieren. Wenn man "typedef typename const ConfirmAllowed<CType*>::type type;" schreibt, wird daraus interessanterweise ein *const, obwohl cas "const" links vom "*" steht.

Alternativ funzt auch:

Code: Alles auswählen

	template<class CType> struct ConfirmAllowed<const CType*>
	{
		typedef typename ConfirmAllowed<const CType>::type* type;
		typedef typename ConfirmAllowed<const CType>::scalarType scalarType;
		static const unsigned int dimensions = ConfirmAllowed<const CType>::dimensions+1;
		static const nByte typeName = ConfirmAllowed<const CType>::typeName;
	};
was ich optisch ein wenig eleganter empfinde, da die pointer to const Variante sich ja genauso zur const Variante verhält wie die pointer to nonconst Version zur nonconst Version.

So, scheint jetzt im Wesentlichen alles so zu funktionieren, wie es soll, auch wenn ich für das Laufzeitverhalten erstmal noch ein bischen Testcode schreiben werde, um sicher zu gehen.
Etwas unglücklich ist noch, dass es bisher nicht möglich ist, Typen zu haben, die nur als skalare Variante erlaubt sind und nicht als arrays, da sich die Klasse nicht kompilieren lässt, wenn für einen Type eine Spezialisierung des ValueObject-Templates existiert, aber keine Varainte des ConfirmAllowed-Templates, aber damit werde ich leben können.

Vielen Dank, Krishty.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:Man beachte im letzten Block, dass es "typedef typename const ConfirmAllowed<CType>::type* type;" heißen muss, um für einen const* zu funktionieren. Wenn man "typedef typename const ConfirmAllowed<CType*>::type type;" schreibt, wird daraus interessanterweise ein *const, obwohl cas "const" links vom "*" steht.
Ja, typedef funktioniert für Typen wie Klammern für Terme:
typedef int * intptr;
const intptr; // evaluiert nicht zu "const int *", sondern zu "const (int *)"

Es ist also nicht einfach ein #define. Und ein Grund mehr, das const als Postfix zu benutzen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Ich habe jetzt neben den Konstruktoren für die Basistypen auch diese beiden Konstruktoren:

Code: Alles auswählen

ValueObject(typename ConfirmAllowed<Etype>::type data, short size);
ValueObject(typename ConfirmAllowed<Etype>::type data, const short* const sizes);
Wenn ich jetzt den oberen Kosntruktor wie folgt aufrufen will:

Code: Alles auswählen

ValueObject<int*>(pVal2, 0)
dann bekomme ich in Visual Studio folgende Fehlermeldung:
error C2668: 'ValueObject<Etype>::ValueObject' : ambiguous call to overloaded function
with
[
Etype=int *
]
could be 'ValueObject<Etype>::ValueObject(int *,const short *const )'
with
[
Etype=int *
]
or 'ValueObject<Etype>::ValueObject(int *,short)'
with
[
Etype=int *
]
while trying to match the argument list '(int *, int)
Sollte der Compiler da nicht ohne expliziten Cast auf short* die short-Variante gegenüber der const short* cosnt Variante bevorzuge, wenn der Call ein int übergibt?

Code: Alles auswählen

ValueObject<int*>(pVal2, (short)0)
funzt natürlich wie erwartet.

Interessanterweise funzt aber auch folgendes ohne Fehlermeldung:

Code: Alles auswählen

int test = 0;
ValueObject<int*>(pVal2, test)
Sollte die hardcodet Konstante 0 nicht ein int sind und damit die Übergabe von 0 den gleichen Downcast verursachen wie die einer lokalen int-Variable?

Noch interessanter wird es, wenn man bedenkt, dass auch folgendes problemlos kompiliert:

Code: Alles auswählen

ValueObject<int*>(pVal2, 1)
Es funktioniert mit 1, aber nicht mit 0? 0 hat demnach einen anderen Standarddatentyp in Visual Studio als 1?

Kann mir wer erklären, was die Ursache dieses seltsamen Verhaltens ist?
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Aramis »

Das ist gemein.

Das Token 0 hat eine Doppelbedeutung in C++ – es ist sowohl das Integer-Literal fuer 0 wie auch ein void*, dessen Wert einer fuer die Zielplattform invaliden Adresse entspricht. Es muesste theoretisch noch nicht einmal die Adresse 0 sein, auch wenn das in der Praxis immer der Fall sein duerfte.

Aus diesem Grunde ist der erste Aufruf zweideutig.

(Genauer: soweit ich weiss, ist das einer der beiden Faelle in C++03 an denen der Compiler so etwas wie Type-Inferenz betreibt und den Typ eines Ausdruckes am umliegenden Kontext abliest. Der explizite static_cast nach short macht dem Compiler also klar, was fuer einen Typ die 0 wirklich haben soll. Wie laecherlich das ist, sieht man schon an der Einfuehrung von nullptr mit C++ 2011 - allerdings entfaellt damit die alte Regel aus Kompatibilitaetsgruenden nicht).
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Aramis hat geschrieben: Es muesste theoretisch noch nicht einmal die Adresse 0 sein.
Urgs, sprich, ein NULL, welches in C als ((void*)0) und in C++ als 0 definiert ist, könnte z.B. auch auf die Speicheradresse 1 verweisen?
Demnach würde dann in dem Fall *(int*)(rand()%2) auf die identische Adresse zugreifen? OK, wäre wohl selbst, wenn ein Compiler das machen würde, nicht praxisrelevant, weil es mir ja Wurst sein kann, ob ich nen EXC_BAD_ACCESS für Adresse 0 oder Adresse 1 bekomme, aber weird ist es dennoch.

Zum eigentlicehn Thema deiner Antwort:
Hmm, man könnte doch in C++ einfach NULL wie in C als ((void*)0) definieren und 0 ohen expliziten void+-Cast immer als int integer-literal interpretieren, bzw. man hätte es bei EInführung des Standards gekonnt, vermutlich gibts inzwischen zu viele Programme, die den Literal übergeben statt einer Konstante für den Nullpointer.
OK, dann weiß ich jetzt zumindest den Hintergrund und das die Problematik nur bei Kombination von Strinliteralen für die Größenangabe und eindimensionalen Arrays der Größe 0 vorkommt. Diese Kombiantion sollte wohl kein all zu häufig vorkommender Fall in der Praxis sein. In dem Fall muss der Benutzer der Klasse dann eben casten, dann kann ich mir Spezialisierungen für eindimensionale Arrays für jeden einzelenen unterstützten Datentyp sparen und brauche sie nur für die Skalartypen.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:Urgs, sprich, ein NULL, welches in C als ((void*)0) und in C++ als 0 definiert ist, könnte z.B. auch auf die Speicheradresse 1 verweisen?
Ja; in einigen Unix-Treibern zeigt 0 (und damit auch nullptr) ganz woanders hin, weil auf ein paar Systemen die tatsächliche Adresse 0x00000000 durch den gültigen Adressbereich des Kernels abgedeckt und damit nutzbar ist.
kaiserludi hat geschrieben:Demnach würde dann in dem Fall *(int*)(rand()%2) auf die identische Adresse zugreifen?
Nein, du kannst diese Adressen nicht vergleichen. Adressen, die nicht per malloc() oder new reserviert sind (plus ein Byte), existieren in C und C++ nicht. Sie sind einfach nicht da. Beide ungültig zwar; aber wenn du es so ausdrückst, versuchst du, etwas nicht existentes mit etwas nicht existentem zu vergleichen.

Es ist ziemlich wichtig, zu verstehen, dass C++’ Zeiger rein symbolisch sind. Sie zeigen nicht auf Adressen, sondern auf Objekte oder auf garnichts (nullptr). (Wenn man das begriffen hat, verhaspelt man sich auch nicht mehr bei Zeigerarithmetik.) Sie könnten auch ganz anders realisiert sein als durch Adressen. Es gibt Architekturen, wo void * und int * unterschiedlich groß sind. Über Speicheradressen nachzudenken hat nichts mit C++-Programmierung zu tun, sondern ist Low-Level-Kram, der in 99 % der Fälle unbedeutend ist. Siehe auch: The Stack Is An Implementation Detail.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Krishty hat geschrieben: Über Speicheradressen nachzudenken hat nichts mit C++-Programmierung zu tun, sondern ist Low-Level-Kram, der in 99 % der Fälle unbedeutend ist.
Ich darf mich in der Praxis auch genug mit Low-Level C-Code und ab und an Inline-Assembler rumschlagen, da ist es schon wichtig, zu wissen, dass Pointer über Speicherbereiche realisiert sind, um Code wie pArray+i*sizeof(int*) nachvollziehen zu können.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

Dann hast du mir was voraus, denn ich kann den nicht wirklich nachvollziehen ;)
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

pArray+i*sizeof(int) ist highlevel im Grunde das Gleiche wie &pArray, wenn pArray als "int* pArray;" definiert ist. Allerdings funktioniert die erste Syntax auch, wenn man es mit einem "void* pArray;" zu tun hat, während die zweite Syntax in dem Fall einen explizen Cast auf int* benötigen würde, um zu wissen, wie viele Bytes im Speicher weiter gehüpft werden muss bis zum nächsten Array-Element, so dass es je nach Compiler Warning oder Error gibt, im ersten Fall undefiniertes Laufzeit-Verhalten, so dass man &((int*)pArray) schreiben müsste.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Benutzeravatar
Krishty
Establishment
Beiträge: 8261
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von Krishty »

kaiserludi hat geschrieben:Allerdings funktioniert die erste Syntax auch, wenn man es mit einem "void* pArray;" zu tun hat, während die zweite Syntax in dem Fall einen explizen Cast auf int* benötigen würde
Nein. Sie funktioniert nur, wenn pArray auf char zeigt, weil void keine Größe hat. Außerdem dürfen Zeiger mit nichts als char * und unsigned char * überlappen, auch nicht mit void * (Strict Aliasing Rule). Glückwunsch; dein Text ist undefiniertes Verhalten.
kaiserludi hat geschrieben: Allerdings funktioniert die erste Syntax auch, wenn […], während die zweite Syntax in dem Fall einen explizen Cast auf int* benötigen würde […], so dass es je nach Compiler Warning oder Error gibt, im ersten Fall undefiniertes Laufzeit-Verhalten, so dass man &((int*)pArray) schreiben müsste.
Nochmal in mehr als einem Satz bitte :D Und &((int*)pArray) gleicht dem klareren ((int*)pArray) + i.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
kaiserludi
Establishment
Beiträge: 467
Registriert: 18.04.2002, 15:31

Re: partielle Template Spezialisierung multi-dimension C-arr

Beitrag von kaiserludi »

Es geht mir um so Code wie z.B. (Achtung, Pseudo-Code):
void* pArray = NULL;
if(condition)
{
pArray = malloc(sizeof(int)*length);
for(init i=0; i<length; i++)
foo(pArray+i*sizeof(int));
}
else
{
pArray = malloc(sizeof(short)*length);
for(init i=0; i<length; i++)
foo(pArray+i*sizeof(short));
}

So was darf ich öfter lesen und muss dann eben wissen, was das eigentlich macht, wozu wiederum relevant ist, wie arrays im Speicher implementiert sind und damit, dass Pointer lowlevel auf Speicheradressen zeigen.
"Mir ist auch klar, dass der Tag, an dem ZFX und Developia zusammengehen werden der selbe Tag sein wird, an dem DirectGL rauskommt."
DirectGL, endlich ist es da
:)

"According to the C++ standard, it's "undefined". That's a technical term that means, in theory, anything can happen: the program can crash, or keep running but generate garbage results, or send Bjarne Stroustrup an e-mail saying how ugly you are and how funny your mother dresses you." :shock:[/size]
Antworten