Ik probeer een generieke image library te schrijven waar ik een beetje hobbymatig mee kan rotzooien, maar loop tegen wat merkwaardige problemen aan.
Image class met pixel policy.
Mijn eigen image class is niet afhankelijk van een bepaald pixel type, ik gebruik een template variable om mijn image structuur te laten weten welk pixel type er gebruikt moet worden. Zie de image als een N-dimensionale container die een willekeurig type pixel opslaat. Bijvoorbeeld grayscale, (A)RGB, CMYK of wat dan ook. Het aantal dimensies van de image is ook variabel, maar dat laat ik even buiten beschouwing.
Casting de pixel buffer naar een ander type.
Omdat het voor image operaties niet altijd gemakkelijk is om te werken met multi channeled pixels moet er soms gecast worden. Dit kan natuurlijk ook mooi middels templates waardoor dit netjes achter de schermen gebeurt, bijvoorbeeld in de desbetreffende image operatie.
Veilig en simpele casting method van image.
Het komt met image operaties nu eenmaal vaak voor dat er gecast moet worden. Een solid_fill methode will niets weten van losse kanalen, maar meer ingewikkelde algoritmen willen deze controle misschien wel hebben. Wat ik heb gedaan is deze safe cast een methode van image laten zijn. Het is een methode die deze cast makkelijker en veiliger maakt. Een cast naar een type met ander formaat wordt afgevangen. Dit zou namelijk desastreus zijn.
Het eigenlijk probleem.
Na deze nogal grote en wellicht irrelevante inleiding komt nu eindelijk het probleem. Indien ik deze cast() methode gebruik in de main functie (main(int argc, char* argv[])) werkt deze prima en doet het zijn werk zonder probleem. Maar indien ik exact dezelfde code gebruik in een andere functie gaat de compiler (gcc version 4.0.1 / powerpc-apple-darwin8) keihard over z'n nek.
Kan iemand mij uitleggen waarom dezelfde code zonder problemen functioneert in de main functie maar in een andere functie tot een error leidt? Ik heb zelf namelijk totaal geen idee.
Image class met pixel policy.
Mijn eigen image class is niet afhankelijk van een bepaald pixel type, ik gebruik een template variable om mijn image structuur te laten weten welk pixel type er gebruikt moet worden. Zie de image als een N-dimensionale container die een willekeurig type pixel opslaat. Bijvoorbeeld grayscale, (A)RGB, CMYK of wat dan ook. Het aantal dimensies van de image is ook variabel, maar dat laat ik even buiten beschouwing.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
| // image class, simplified: template <typename P> struct image { P* data; // the buffer that stores pixel data image(int w, int h) {...} // constructor }; // 4-channel ARGB pixel: struct argb_32b { unsigned char c[4]; }; image<argb_32b>* img = new image<argb_32b>(320, 200); |
Casting de pixel buffer naar een ander type.
Omdat het voor image operaties niet altijd gemakkelijk is om te werken met multi channeled pixels moet er soms gecast worden. Dit kan natuurlijk ook mooi middels templates waardoor dit netjes achter de schermen gebeurt, bijvoorbeeld in de desbetreffende image operatie.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| template <typename P, typename T> void solid_fill(image<P>* img, T p) { // decides compile whether to throw runtime if (sizeof(P) != sizeof(T)) throw std::bad_cast(); T* data = reinterpret_cast<T*>(img->data); // for all x and all y { data[y * img->width() + x] = p; // } } // now both ways possible: solid_fill(img, 0x00FF0000); argb_32b p(0, 0xFF, 0, 0); solid_fill(img, p); |
Veilig en simpele casting method van image.
Het komt met image operaties nu eenmaal vaak voor dat er gecast moet worden. Een solid_fill methode will niets weten van losse kanalen, maar meer ingewikkelde algoritmen willen deze controle misschien wel hebben. Wat ik heb gedaan is deze safe cast een methode van image laten zijn. Het is een methode die deze cast makkelijker en veiliger maakt. Een cast naar een type met ander formaat wordt afgevangen. Dit zou namelijk desastreus zijn.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // image class, simplified: template <typename P> struct image { P* data; // the buffer that stores pixel data template <typename T> inline T* cast() const throw() { if (sizeof(T) << 3 != P::bpp) throw std::bad_cast(); return reinterpret_cast<T*>(data); } }; |
Het eigenlijk probleem.
Na deze nogal grote en wellicht irrelevante inleiding komt nu eindelijk het probleem. Indien ik deze cast() methode gebruik in de main functie (main(int argc, char* argv[])) werkt deze prima en doet het zijn werk zonder probleem. Maar indien ik exact dezelfde code gebruik in een andere functie gaat de compiler (gcc version 4.0.1 / powerpc-apple-darwin8) keihard over z'n nek.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| template <typename P, typename T> void solid_fill(image<P>* img, T p) { img->cast<T>()[0] = p; // Both these lines fail with a compiler error. img->cast<int>()[0] = 10; // error: expected primary-expression before '<' token // error: expected primary-expression before 'int' // error: expected ',' or ';' before 'int' } int main (int argc, char *argv[]) { image_2d<argb_32b>* img = new image_2d<argb_32b>(640, 480); img->cast<int>()[0] = 0x00FF0000; // Compiles and works fine. solid_fill(img, 0x00FF0000); delete img; } |
Kan iemand mij uitleggen waarom dezelfde code zonder problemen functioneert in de main functie maar in een andere functie tot een error leidt? Ik heb zelf namelijk totaal geen idee.