Template Parameter bestimmt Anzahl der Funktionsparameter
-
Shade Of Mine schrieb:
variadic templates kommen nicht ganz hin, da ich die Parameter ja normal an die Funktion uebergeben will.
Daran wird es nicht scheitern. Obiger Funktion kannst du die Parameter ganz normal übergeben

Wie dann fortzusetzen wäre, ist natürlich eine andere Frage. Naheliegend wäre, deine bereits bestehende Varargs-Variante zu nehmen und nur mit obigem Funktionstemplate abzusichern.
Shade Of Mine schrieb:
aber da ich diese auf aktuellen compilern nicht verwenden kann ist es sowieso leider keine annehmbare loesung.
Ja, daran scheitert es schon eher

Shade Of Mine schrieb:
Die Funktion erstellt nur ein N Dimensionales Array (Size definiert die anzahl der dimensionen) und die einzelnen parameter definieren wie gross die jeweilige dimension ist.
Ah, sag das doch gleich

Welche Erwartungen hast du an die Funktion? Soll sie einfach nur einen korrekt typisierten Zeiger auf ein bereits alloziertes Array zurückgeben? Dann würde ich vielleicht so etwas machen:
template <typename T, unsigned Dim> struct ArrayT { typedef typename ArrayT <T, Dim - 1>::type* type; }; template <typename T> struct ArrayT <T, 0> { typedef T type; }; template <typename T, unsigned Dim> struct ArrayCreator { unsigned sizeArray[Dim ? Dim : 1]; // avoid error for Dim == 0 typedef typename ArrayT <T, Dim>::type ArrayType; ArrayCreator <T, Dim + 1> operator [] (unsigned size) const { ArrayCreator <T, Dim + 1> retval; for (unsigned i = 0; i != Dim; ++i) retval.sizeArray[i] = sizeArray[i]; retval.sizeArray[Dim] = size; return retval; } operator ArrayType (void) const { // TODO: allocate the array } }; template <typename T> ArrayCreator <T, 0> createArray (void) { return ArrayCreator <T, 0> (); }Benutzung so:
int main (void) { // Viel Vergnügen beim exceptionsicheren Freigeben. int******** ia = createArray <int> ()[10][20][30][40][50][60][70][80]; return 0; }Aber wozu man so etwas brauchen könnte, weiß ich trotzdem nicht.
-
ich nehme an, du meinst sowas:
#include <iostream> using namespace std; class MultiDimesionArray{ public: MultiDimesionArray(size_t count,size_t* arr){ for(size_t i=0;i!=count;++i) cout<<arr[i]<<' '; cout<<'\n'; } }; template<int Count> struct InitArray{ size_t data[Count]; }; template<size_t Count,size_t Index> void initInitArray(InitArray<Count> &arr){ } template<size_t Count,size_t Index,typename ST,typename... Tail> void initInitArray(InitArray<Count> &arr,ST head,Tail... tail){ static_assert(Count-Index-1==sizeof...(Tail),"wrong number of arguments"); arr.data[Index]=head; initInitArray<Count,Index+1>(arr,tail...); } template<size_t Count,typename... Args> MultiDimesionArray create(Args... args){ static_assert(sizeof...(Args)==Count,"wrong number of arguments"); InitArray<Count> result; initInitArray<Count,0>(result,args...); return MultiDimesionArray(Count,result.data); } int main(){ create<3>(11,12,13); return 6; }ausgabe
11 12 13int main(){ create<3>(11,12,13,14);ausgabe
i686-mingw32-c++ -Wall -fno-enforce-eh-specs -march=athlon -O3 -fno-rtti -std=gn u++0x -pipe -DNDEBUG -o test.exe main.o main.cpp: In function 'MultiDimesionArray create(Args ...) [with unsigned int Co unt = 3u, Args = int, int, int, int]': main.cpp:38: instantiated from here main.cpp:31: error: static assertion failed: "wrong number of arguments" main.cpp: In function 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 0u, ST = int, Tail = int, int, in t]': main.cpp:33: instantiated from 'MultiDimesionArray create(Args ...) [with unsi gned int Count = 3u, Args = int, int, int, int]' main.cpp:38: instantiated from here main.cpp:24: error: static assertion failed: "wrong number of arguments" main.cpp: In function 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 1u, ST = int, Tail = int, int]': main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 0u, ST = int, Tail = i nt, int, int]' main.cpp:33: instantiated from 'MultiDimesionArray create(Args ...) [with unsi gned int Count = 3u, Args = int, int, int, int]' main.cpp:38: instantiated from here main.cpp:24: error: static assertion failed: "wrong number of arguments" main.cpp: In function 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 2u, ST = int, Tail = int]': main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 1u, ST = int, Tail = i nt, int]' main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 0u, ST = int, Tail = i nt, int, int]' main.cpp:33: instantiated from 'MultiDimesionArray create(Args ...) [with unsi gned int Count = 3u, Args = int, int, int, int]' main.cpp:38: instantiated from here main.cpp:24: error: static assertion failed: "wrong number of arguments" main.cpp: In function 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 3u, ST = int, Tail = ]': main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 2u, ST = int, Tail = i nt]' main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 1u, ST = int, Tail = i nt, int]' main.cpp:26: instantiated from 'void initInitArray(InitArray<Count>&, ST, Tail ...) [with unsigned int Count = 3u, unsigned int Index = 0u, ST = int, Tail = i nt, int, int]' main.cpp:33: instantiated from 'MultiDimesionArray create(Args ...) [with unsi gned int Count = 3u, Args = int, int, int, int]' main.cpp:38: instantiated from here main.cpp:24: error: static assertion failed: "wrong number of arguments" make: *** [main.o] Error 1mausklick eins höher als die markierte fehlermeldung wirft auf
create<3>(11,12,13,14);mit
template<size_t Dimensions> class MultiDimesionArray{ public: MultiDimesionArray(size_t* arr){ for(size_t i=0;i!=Dimensions;++i) cout<<arr[i]<<' '; cout<<'\n'; } };und
template<size_t Count,typename... Args> MultiDimesionArray<Count> create(Args... args){ static_assert(sizeof...(Args)==Count,"wrong number of arguments"); InitArray<Count> result; initInitArray<Count,0>(result,args...); return MultiDimesionArray<Count>(result.data); }gehts auch.
falls du cout<<mda[4][3][5] haben willst, brauchste die anzahl der dimensionen wohl als compilezeit-konstante.das alles sollte aber in die richtung
create<3>{11,12,13};gehen.
-
@audacia|off:
Natuerlich ist das Array in eine Klasse gekapselt. Das ist ja der Sinn der Sache. Du schreibstarray_n<int, 3> arr(1,2,3); arr[0][0][0]=7;und fertig. array_n ist auch so clever nur eine allokation zu machen...
@volkard:
sehr nett.
morgen werde ich mir das mal etwas naeher ansehen um es ganz zu verstehen.dann setzt die sichere variante halt einfach wirklich variadic templates voraus - wer das nicht hat muss mit der unsicheren variante mit laufzeitfehlern leben...
falls noch jemanden eine sichere variante ohne variadic templates einfaellt - nur her damit. aber ich fuerchte fast dass das nicht gehen wird...
danke jedenfalls.
-
Ich hab mal ein wenig herumgespielt, folgendes ist ein wenig umständlich, ich weiß nicht wie gut Compiler das weg-optimieren können und die doppelte Typ-Angabe ist umständlich; sonst find ich's aber schön :):
template<typename T, unsigned int Size> class array_n { private: template<unsigned int CurSize> struct MakeList { MakeList( T* t ) { for ( int i=0; i<CurSize-1; ++i ) elems[i] = t[i]; } MakeList<CurSize+1> operator()( T t ) { elems[CurSize-1] = t; return MakeList<CurSize+1>( &elems[0] ); } int elems[CurSize]; }; template<> struct MakeList<1> { MakeList( T t ) : elem(t) { } MakeList<2> operator()( T t ) { return MakeList<2>( &elem ); } int elem; }; public: typedef MakeList<1> Dims; public: array_n( const MakeList<Size>& dims ) { } }; void main() { array_n<int,4> a( array_n<int,4>::Dims(1) (2) (3) (4) ); }Das Konzept ist an boost::list_of angelehnt.
-
Shade Of Mine schrieb:
Natuerlich ist das Array in eine Klasse gekapselt. Das ist ja der Sinn der Sache. Du schreibst
array_n<int, 3> arr(1,2,3); arr[0][0][0]=7;und fertig. array_n ist auch so clever nur eine allokation zu machen...
Abgesehen davon, daß du nicht die Konstruktorschreibweise benutzen kannst, dürfte das mit meiner Variante durchaus umsetzbar sein. ([] finde ich für Array-Dimensionen ohnehin intuitiver.)
Badestrands Version ist eigentlich genau das gleiche, nur mit () anstatt [].
-
ich bin fast sicher, Shade will hochdimensionale arrays als hashtables abspeichern, wobei beim zugriff dann einfach die indizes gehasht werden und als ersten suchkey genommen werden. vielleicht hat er auch keine lust und nimmt innendrin eine std::multimap.
aber bestimmt baut er keine echten 8-dimensionalen arrays, so ein winziges achtdimensionales int[13][16][25][22][13][24][16][24] braucht nämlich schon 51 terabyte. nichtmal ein mac hat so viel speicher. ich bezweifle daher, daß das rekursive aufbauen des arrays sachdienlich ist, und hab ihm die parameter als array in die hand gegeben.
-
volkard schrieb:
aber bestimmt baut er keine echten 8-dimensionalen arrays, so ein winziges achtdimensionales int[13][16][25][22][13][24][16][24] braucht nämlich schon 51 terabyte.
Ungefähr dahin zielte mein Beispiel

volkard schrieb:
ich bezweifle daher, daß das rekursive aufbauen des arrays sachdienlich ist, und hab ihm die parameter als array in die hand gegeben.
Genau das tut meine Lösung auch. Ob man nun das Array im operator T********() anhand dieser Liste konstruiert oder ob die Array<T,Dim>-Klasse einen Konstruktor für ArrayCreator<T,Dim>-Objekte definiert und dort anhand von ArrayCreator<T,Dim>::sizeArray den benötigten Speicher alloziert, ist prinzipiell unerheblich.
-
array_n<int,4> a( array_n<int,4>::Dims(1) (2) (3) (4) );Das existiert mit Hilfe von inline_containern bereits. Aber danke

@volkard:
In der Tat gibt es 2 Varianten:
array_n<> dass ein mehrdimensionales array auf einem eindimensionalen abbildet. Das eignet sich natürlich nur für kleine größen. Aber dafür finde ich es unheimlich praktisch. Vorallem da duarray<int, 3> arr(1,2,3); foo(arr[0].begin(), arr[0].end());machen kannst.
Und es gibt ein multi_array<> das das ganze per std::map löst (wobei mir die implementierung noch nicht so gefällt - ich bin da eher erst am interface dran).
Das bietet natürlich größere mehrdimensionale arrays aber man kann nicht über eine dimension iterieren. aber multi_array ist noch nicht fertig. array_n dagegen verwende ich schon.
-
audacia schrieb:
Badestrands Version ist eigentlich genau das gleiche, nur mit () anstatt [].
Ups, das war mir nicht klar, jetzt sehe ich's aber auch

Shade Of Mine schrieb:
dann setzt die sichere variante halt einfach wirklich variadic templates voraus - wer das nicht hat muss mit der unsicheren variante mit laufzeitfehlern leben...
Was spricht denn bei der "unsicheren" Variante gegen audacias/meine/deine-inline-container Lösung?
-
Badestrand schrieb:
Was spricht denn bei der "unsicheren" Variante gegen audacias/meine/deine-inline-container Lösung?
Sieht hässlich aus.
Es geht hier nur um reine Ästhetik - die Funktionalität ist ja bereits vorhanden. Die variadic Template Variante ist zB sehr schön.
-
Shade Of Mine schrieb:
Badestrand schrieb:
Was spricht denn bei der "unsicheren" Variante gegen audacias/meine/deine-inline-container Lösung?
Sieht hässlich aus.
Es geht hier nur um reine Ästhetik - die Funktionalität ist ja bereits vorhanden. Die variadic Template Variante ist zB sehr schön.
Dann spezielisier den ctor für Dimensionszahlen bis vielleicht 4 oder 5. Oder gleich 10.
Die hässliche Variante kannst du dann immer verwenden, und bei "normalen" Arrays auch die schönere.So würde ich es zumindest machen. Wenn dann variadic templates mal kommen kann man ja jederzeit die Implementierung anpassen, so dass die "schöne" Version mit allen Dimensionszahlen verwendet werden kann - der Client-Code ändert sich dadurch ja nicht.
-
Shade Of Mine schrieb:
Sieht hässlich aus.
Zumindest mit eckigen Klammern ist das recht nah an der üblichen Syntax für Array-Deklarationen. Was ist da häßlich?
Ansonsten befolge hustbaers Vorschlag.
-
p.S.: ich finde üble Code-Wiederholung, wie sie für die erwähnte Spezialisierung nötig wäre, bzw. den grenzwertigen Einsatz von Makros mit dem man es auch machen kann, zwar nicht schön, aber in Library-Code durchaus vertretbar. Nämlich wenn sich dadurch für den User-Programmer Vorteile ergeben.
In dem Fall wäre das ja so, und daher fände ich es auch OK.