Beetje vage topictitel, maar zo ongeveer de beste die ik kan bedenken dat de lading ook echt dekt.
Ik heb een template matrix class, met 4 parameters, het aantal rijen, het aantal kolommen, het type, en een stride
De elementen worden opgeslagen als T[ROWS][COLS], maar ipv het aantal kolommen gebruik ik hier de stride parameter. Dit doe ik om een kolom op te kunnen vragen, zonder daar ruimte voor te moeten reserveren. De kolom staat dan gewoon in het geheugen-gebied van de totale matrix, alleen het type is anders.
Een lap code zegt meer dan 1000 woorden, dus op dit moment in mijn uitleg heb ik dit:
Goed, nou heb ik natuurlijk ook een overloaded operator =, die een matrix van dezelfde afmeting kan assignen aan een andere
dit is een template functie omdat de stride van 2 matrices natuurlijk niet per se gelijk hoeft te zijn... zolang het aantal rijen en kolommen en het type maar kloppen
Nou vind ik het wel fijn als je een assignment als dit kunt doen:
Dit is mogelijk omdat je de "," operator kunt overloaden, en die operator een hele lage precedence heeft (en bovendien links associatief is)
Het wordt dus geparsed als (((m = 1), 2), 3). De assignment m = 1 moet dus een object retourneren dat de matrix waarop ie werkt en de index van het huidige element bijhoudt.
Hier gebruik ik een template structure voor met een int parameter INDEX. De matrix waarop ie werkt hou ik bij in de this pointer, het adres van dit object wordt dus ook gewoon het adres van de matrix. Er wordt dan geen temporary object aangemaakt, en kan de assignment compleet geoptimaliseert worden door de compiler
Dit komt er dan bij in de class
Een dergelijke constructie natuurlijk ook voor rijen, maar die doen er nu even niet toe
Wat is het probleem nu? De assignment van een kolom is ambiguous. Waarom? Omdat een matrix deze 2 functies heeft:
Alleen als COLS gelijk is aan 1, dan is die functie dubbel.
Mijn vraag is nu: hoe kan ik dat oplossen?
Ik heb al een aantal mogelijkheden bedacht, maar geen van die vind ik echt mooi
Ten eerste kun je natuurlijk een partial specialization doen, waarbij de extra operator = niet gedefinieerd is als het aantal kolommen gelijk is aan 1. Alleen moet je daar de hele matrix struct opnieuw voor definieren, wat ik nogal een rompslomp vindt. Bovendien moet ik dat dan ook doen wanneer het aantal rijen gelijk is aan 1, en ook nog eens als ze beide 1 zijn. Niet echt een optie dus
De andere is een andere operator definieren voor die assignment. Operator << lijkt me dan de mooiste, maar ik wil het eigenlijk bij = houden
Is er misschien een manier om de ambiguiteit op te lossen zonder een functiedefinitie weg te halen? Of kun je een functie definitie niet laten meecompilen als ROWS of COLS gelijk is aan 1 (een soort van #ifdef zeg maar, maar dan met template constructies)
Of misschien is er een trucje om de 1e operator = meer gespecializeerd te laten zijn dan de 2e, waardoor de 1e altijd gekozen wordt als ze beide mogelijk zijn?
Ik hoop dat iemand een oplossing kan bedenken
Zo niet dan ga ik waarschijnlijk voor de << variant
Ik heb een template matrix class, met 4 parameters, het aantal rijen, het aantal kolommen, het type, en een stride
De elementen worden opgeslagen als T[ROWS][COLS], maar ipv het aantal kolommen gebruik ik hier de stride parameter. Dit doe ik om een kolom op te kunnen vragen, zonder daar ruimte voor te moeten reserveren. De kolom staat dan gewoon in het geheugen-gebied van de totale matrix, alleen het type is anders.
Een lap code zegt meer dan 1000 woorden, dus op dit moment in mijn uitleg heb ik dit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| template <int ROWS, int COLS, class T = float, int STRIDE = COLS> struct matrix { typedef matrix<1, COLS, T, STRIDE> row_type; typedef matrix<ROWS, 1, T, STRIDE> col_type; T buffer[ROWS][STRIDE]; row_type & row (int index) { return reinterpret_cast<row_type &> (buffer[index][0]); } col_type & col (int index) { return reinterpret_cast<col_type &> (buffer[0][index]); } }; |
Goed, nou heb ik natuurlijk ook een overloaded operator =, die een matrix van dezelfde afmeting kan assignen aan een andere
C++:
1
2
3
4
5
6
| // in de definitie van matrix<ROWS, COLS, T, STRIDE> template <int S> matrix & operator = (const matrix<ROWS, COLS, T, S> & other) { // kopieer de data van other naar this } |
dit is een template functie omdat de stride van 2 matrices natuurlijk niet per se gelijk hoeft te zijn... zolang het aantal rijen en kolommen en het type maar kloppen
Nou vind ik het wel fijn als je een assignment als dit kunt doen:
C++:
1
2
3
4
5
6
7
8
| matrix<1, 3> m; m = 1, 2, 3; //of met kolommen tegelijk: matrix<3, 3> m; matrix<1, 3> col1, col2, col3; m = col1, col2, col3; |
Dit is mogelijk omdat je de "," operator kunt overloaden, en die operator een hele lage precedence heeft (en bovendien links associatief is)
Het wordt dus geparsed als (((m = 1), 2), 3). De assignment m = 1 moet dus een object retourneren dat de matrix waarop ie werkt en de index van het huidige element bijhoudt.
Hier gebruik ik een template structure voor met een int parameter INDEX. De matrix waarop ie werkt hou ik bij in de this pointer, het adres van dit object wordt dus ook gewoon het adres van de matrix. Er wordt dan geen temporary object aangemaakt, en kan de assignment compleet geoptimaliseert worden door de compiler
Dit komt er dan bij in de class
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| // in de definitie van matrix<ROWS, COLS, T, STRIDE> template <int INDEX> struct col_setter { template<int S> col_setter<INDEX + 1> & operator , (const matrix<ROWS, 1, T, S> & col) { matrix & m = reinterpret_cast (matrix &) (*this); m.col (INDEX) = col; return reinterpret_cast<col_setter<INDEX + 1> > (*this); } }; template <int S> col_setter<1> & operator = (const matrix<ROWS, 1, T, S> & col) { this->col (0) = col; return reinterpret_cast<col_setter<1> &> (*this); } |
Een dergelijke constructie natuurlijk ook voor rijen, maar die doen er nu even niet toe
Wat is het probleem nu? De assignment van een kolom is ambiguous. Waarom? Omdat een matrix deze 2 functies heeft:
C++:
1
2
3
4
5
6
| // in de definitie van matrix<ROWS, COLS, T, STRIDE> template <int S> matrix & operator = (const matrix<ROWS, COLS, T, S> & other); template <int S> col_setter<1> & operator = (const matrix<ROWS, 1, T, S> & col); |
Alleen als COLS gelijk is aan 1, dan is die functie dubbel.
Mijn vraag is nu: hoe kan ik dat oplossen?
Ik heb al een aantal mogelijkheden bedacht, maar geen van die vind ik echt mooi
Ten eerste kun je natuurlijk een partial specialization doen, waarbij de extra operator = niet gedefinieerd is als het aantal kolommen gelijk is aan 1. Alleen moet je daar de hele matrix struct opnieuw voor definieren, wat ik nogal een rompslomp vindt. Bovendien moet ik dat dan ook doen wanneer het aantal rijen gelijk is aan 1, en ook nog eens als ze beide 1 zijn. Niet echt een optie dus
De andere is een andere operator definieren voor die assignment. Operator << lijkt me dan de mooiste, maar ik wil het eigenlijk bij = houden
Is er misschien een manier om de ambiguiteit op te lossen zonder een functiedefinitie weg te halen? Of kun je een functie definitie niet laten meecompilen als ROWS of COLS gelijk is aan 1 (een soort van #ifdef zeg maar, maar dan met template constructies)
Of misschien is er een trucje om de 1e operator = meer gespecializeerd te laten zijn dan de 2e, waardoor de 1e altijd gekozen wordt als ze beide mogelijk zijn?
Ik hoop dat iemand een oplossing kan bedenken
Zo niet dan ga ik waarschijnlijk voor de << variant
[ Voor 3% gewijzigd door .oisyn op 26-04-2003 19:38 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.