partielle Template Spezialisierung multi-dimension C-arrays
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
partielle Template Spezialisierung multi-dimension C-arrays
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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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>>>), "!!");
Gruß, Ky
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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);
};
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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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.kaiserludi hat geschrieben:wobei sizes ein eindimensionaler array wäre mit so vielen Elementen, wie Parameter 1 an Dimensionen hat.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Was den die Längen angeht, komme ich bei c-arrays eh nicht drum herum, die durch den Aufrufer übergeben zu lassen.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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);
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; };
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; };
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.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Ein Aufruf wie folgt:
Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<TCConfirmAllowed<nByte**>>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
obwohl die Klasse nun folgenden Konstruktor deklariert:error C2661: 'ValueObject<Etype>::ValueObject' : no overloaded function takes 3 arguments
Code: Alles auswählen
template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int dimension, const short* sizes);
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]
Re: partielle Template Spezialisierung multi-dimension C-arr
Kann mich irren aber muss das nicht so heißen?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));
Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<nByte**>(TCConfirmAllowed<nByte**>::type((nByte**)NULL), 3, (short*)NULL));
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Habe ich auch ausprobiert, aber führt zur gleichen Fehlermeldung.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));
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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);
Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte**)NULL, 3, (short*)NULL));
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));
und bei
Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
Lasst euch btw. nicht durch das nByte verwirren, dass ist einfach nur als unsigned char definiert.
wie sähe das denn syntaktisch im Code aus?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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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: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);
kaiserludi hat geschrieben:Blooß wie würde ich jetzt einen 3-dimensionalen nByte-array übergeben, also nByte*** ?
Bei dem Codevermeldet VS "none of the 28 overloads could convert all the argument types while trying to match the argument list '(unsigned char, int, short *)"Code: Alles auswählen
ev.put(KeyObject<JString>("test"), EValueObject<nByte***>(TCConfirmAllowed<nByte***>::type((const nByte***)NULL), 3, (short*)NULL));
und beiheißt es "none of the 28 overloads could convert all the argument types while trying to match the argument list '(const nByte ***, int, short *)"Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
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.Krishty hat geschrieben:Code: Alles auswählen
class ValueObject {´ … template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)kaiserludi hat geschrieben:wie sähe das denn syntaktisch im Code aus?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.
Btw – bei 28 Konstruktoren hoffe ich, dass du niemals mehr was an der Klasse ändern müssen wirst.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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: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: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);
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:Blooß wie würde ich jetzt einen 3-dimensionalen nByte-array übergeben, also nByte*** ?
Bei dem Codevermeldet VS "none of the 28 overloads could convert all the argument types while trying to match the argument list '(unsigned char, int, short *)"Code: Alles auswählen
ev.put(KeyObject<JString>("test"), EValueObject<nByte***>(TCConfirmAllowed<nByte***>::type((const nByte***)NULL), 3, (short*)NULL));
und beiheißt es "none of the 28 overloads could convert all the argument types while trying to match the argument list '(const nByte ***, int, short *)"Code: Alles auswählen
ev.put(KeyObject<JString>("test"), ValueObject<nByte**>((const nByte***)NULL, 3, (short*)NULL));
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.Krishty hat geschrieben:Code: Alles auswählen
class ValueObject {´ … template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
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.Krishty hat geschrieben:Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)kaiserludi hat geschrieben:wie sähe das denn syntaktisch im Code aus?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.
Btw – bei 28 Konstruktoren hoffe ich, dass du niemals mehr was an der Klasse ändern müssen wirst.
Die Klasse besteht auch fast nur aus Konstruktoren, ansonsten gibts nur noch getDataCopy(), getDataAdress(), eine private Helpermethode und einen Destruktor.
EDIT:
Hmm, da meint VS dann:Krishty hat geschrieben:Indem vor dem TCConfirmAllowed<nByte**>::type((nByte**)NULL) noch ein typename stünde? ;)kaiserludi hat geschrieben:wie sähe das denn syntaktisch im Code aus?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.
EDIT2: fixed quotes von Edit1error C2899: typename cannot be used outside a template declaration
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
Okay. Falls du irgendwann den Überladungsdruck senken willst, sehe ich da aber eine Möglichkeit.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.
Ja, genau – und, wessen Typs die finalen Array-Elemente sind. Du musst dazu template <> struct TCConfirmAllowed<int> { typedef int type; }; zukaiserludi 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?
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
};
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
};
(Das sollte dann auch der Punkt sein, an dem ich es mir selber nachbaue statt alles aus dem Kopf zu machen.)
Weil du noch in dem nicht-ge-template-ten Konstruktor bist. Sobald er ein Template ist, muss das typename dahin.kaiserludi hat geschrieben:Hmm, da meint VS dann:error C2899: typename cannot be used outside a template declaration
————
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
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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.
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]
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Code: Alles auswählen
template <typename CType> ValueObject(typename TCConfirmAllowed<CType>::type data, int const * sizes);
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!
}
};
http://learningcppisfun.blogspot.com/20 ... licit.html
hat wer eine alternative Idee zur Lösung des ursprünglichen Problems?
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]
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Folgendes funktioniert:
Code: Alles auswählen
template<typename Etype>
class VObject:public Object
{
public:
VObject(typename TCConfirmAllowed<Etype>::type data)
{
}
};
Code: Alles auswählen
int**** temp;
VObject<int****> bla(temp);
Code: Alles auswählen
char foo;
VObject<char> bla(foo);
Code: Alles auswählen
char foo;
VObject<int> bla(foo);
Code: Alles auswählen
char* foobar;
VObject<char*> bla(foobar);
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;
};
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]
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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;
};
Folgender Aufruf funktioniert:
Code: Alles auswählen
ValueObject<int*>((int*)NULL, (short*)NULL);
Code: Alles auswählen
ValueObject<const int*>((const int*)NULL, (short*)NULL);
Wie muss ich vorgehen, um das ganze für const int* zum Laufen zu bekommen?
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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;
};
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;
};
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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
Ja, typedef funktioniert für Typen wie Klammern für Terme: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.
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.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
Code: Alles auswählen
ValueObject(typename ConfirmAllowed<Etype>::type data, short size);
ValueObject(typename ConfirmAllowed<Etype>::type data, const short* const sizes);
Code: Alles auswählen
ValueObject<int*>(pVal2, 0)
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?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)
Code: Alles auswählen
ValueObject<int*>(pVal2, (short)0)
Interessanterweise funzt aber auch folgendes ohne Fehlermeldung:
Code: Alles auswählen
int test = 0;
ValueObject<int*>(pVal2, test)
Noch interessanter wird es, wenn man bedenkt, dass auch folgendes problemlos kompiliert:
Code: Alles auswählen
ValueObject<int*>(pVal2, 1)
Kann mir wer erklären, was die Ursache dieses seltsamen Verhaltens ist?
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]
- 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
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).
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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?Aramis hat geschrieben: Es muesste theoretisch noch nicht einmal die Adresse 0 sein.
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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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: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?
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.kaiserludi hat geschrieben:Demnach würde dann in dem Fall *(int*)(rand()%2) auf die identische Adresse zugreifen?
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.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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.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.
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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]
- Krishty
- Establishment
- Beiträge: 8350
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: partielle Template Spezialisierung multi-dimension C-arr
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 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
Nochmal in mehr als einem Satz bitte :D Und &((int*)pArray) gleicht dem klareren ((int*)pArray) + i.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.
-
- Establishment
- Beiträge: 467
- Registriert: 18.04.2002, 15:31
Re: partielle Template Spezialisierung multi-dimension C-arr
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.
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]