Typkonvertierungsproblem



  • Um das eigentliche Problem auf den Nenner zu bringen:

    Wie kann ich am einfachsten einen Zeiger erstellen, der auf ein Objekt z.B. vom Typ float[3] zeigt?

    Denn wenn ich folgendes mache...

    float blah[3];

    ... ist blah ja ein Zeiger auf ein Objekt des Types float, nicht aber float[3] - so wie ich es brauche.

    Wenn ich wie vorgeschlagen folgendes mache:

    template<class T, int i>
    void foo(T bar[i])
    {
        ...
    }
    

    ... ist der Parameter ja ein Array aus i Elementen des Types T.
    Das bringt mir nichts weil ich ja einen Zeiger übergeben will und gleichzeitig den Typ (also z.B. float[3]) für das Template übermitteln muss.



  • sqrt(-1) schrieb:

    Michael E. schrieb:

    Ich versteh immer noch nicht, wieso meine zwei Funktionen nicht helfen.

    Ich will an die Template Funktion doch nur einen Zeiger übergeben.
    Der Typ worauf der Zeiger zeigt ist einer von denen:

    float[3]
    float
    byte[4]
    float[2]
    short

    Dein Template-Vorschlag würde bei der Übergabe eines Zeiger aber eine Array von Zeigern als Parameter annehmen, oder?

    template<class T, int i>
    void foo(T bar[i])    // bekommt ein eindimensionales Array, also sozusagen T*
    {
        ...
    }
    
    template<class T, int i, int j>
    void foo(T bar[i][j])    // erhält ein zweidimensionales Array, also sozusagen T**
    {
        ...
    }
    

    Wie groß ist bei dir n?

    Irgend eine Zahl, z.B. 40.[/quote]
    Damit ist mir nicht geholfen. Ist das irgendeine ganz rein zufällige Zahl? Ich glaub eher nicht.



  • Also es funktioniert z.B. folgendes:

    struct _ElementTypA
    {
      float Element[3];
    }*ElementTypA;
    
    struct _ElementTypB
    {
      float Element;
    }*ElementTypB;
    
    ElementTypA = (_ElementTypA*)getVoidPointer();
    ElementTypB = (_ElementTypB*)getVoidPointer();
    
    schreibeArray(ElementTypA);
    schreibeArray(ElementTypB);
    
    template <class _ElementTyp> void schreibeArray(_ElementTyp* ElementTyp)
    {
       ElementType ArrayPuffer[100];
    
       for(int i=0; i<100; i++)
       {
         ArrayPuffer[i] = *(ArrayPointer+i);
       }
       ...  
    }
    

    Strukturen sind wirken da jedoch ziemlich umständlich.
    Gibt es da nicht etwas "schöneres"?



  • Achja, habe das oben gezeigt nicht getestet, der Compiler nimmt es jedoch an.



  • Wenn dein Compiler es schluckt, kann ich ja Schreibfehler ausschließen.

    Was ist ElementType? Wie sieht getVoidPointer aus?



  • Ups, habe falschen Code genommen.
    So sieht er richtig aus:

    struct _ElementTypA
    {
      float Element[3];
    }*ElementTypA;
    
    struct _ElementTypB
    {
      float Element;
    }*ElementTypB;
    
    ElementTypA = (_ElementTypA*)getVoidPointer();
    ElementTypB = (_ElementTypB*)getVoidPointer();
    
    schreibeArray(ElementTypA);
    schreibeArray(ElementTypB);
    
    template <class _ElementTyp> void schreibeArray(_ElementTyp* ElementTyp)
    {
       ElementTyp ArrayPuffer[100];
    
       for(int i=0; i<100; i++)
       {
         ArrayPuffer[i] = *(ArrayPointer+i);
       }
       ...  
    }
    

    Also ElementTyp, und nicht ElementType.

    getVoidPointer() verdeutlicht einfach das ich einen void-Zeiger zuweise.
    In Wirklichkeit wird der von einer Element-Typ spezifischen Funktion übergeben.



  • Raaahhh! Schon wieder ein Tippfehler:

    struct _ElementTypA
    {
      float Element[3];
    }*ElementTypA;
    
    struct _ElementTypB
    {
      float Element;
    }*ElementTypB;
    
    ElementTypA = (_ElementTypA*)getVoidPointer();
    ElementTypB = (_ElementTypB*)getVoidPointer();
    
    schreibeArray(ElementTypA);
    schreibeArray(ElementTypB);
    
    template <class _ElementTyp> void schreibeArray(_ElementTyp* ElementTyp)
    {
       _ElementTyp ArrayPuffer[100];
    
       for(int i=0; i<100; i++)
       {
         ArrayPuffer[i] = *(ArrayPointer+i);
       }
       ...  
    }
    

    So, jetzt sollte es stimmen.

    Keine Vorschläge für eine schönere Alternative zu den Strukturen?



  • Und dein Compiler soll das da geschluckt haben? Dann fehlen mir aber noch Infos. Was is ArrayPointer? Wo verwendest du den Parameter ElementTyp in der Funktion?



  • Arrr.... ArrayPointer war auch noch ein Relikt aus meinem ursprünglichen Code

    [code]
    struct _ElementTypA
    {
    float Element[3];
    }*ElementTypA;

    struct _ElementTypB
    {
    float Element;
    }*ElementTypB;

    ElementTypA = (_ElementTypA*)getVoidPointer();
    ElementTypB = (_ElementTypB*)getVoidPointer();

    schreibeArray(ElementTypA);
    schreibeArray(ElementTypB);

    template <class _ElementTyp> void schreibeArray(_ElementTyp* ElementTyp)
    {
    _ElementTyp ArrayPuffer[100];

    for(int i=0; i<100; i++)
    {
    ArrayPuffer[i] = *(ElementTyp+i);
    }
    ...
    }[code]

    Ob es jetzt endlich stimmt? 😉



  • Arrr.... ArrayPointer war auch noch ein Relikt aus meinem ursprünglichen Code

    struct _ElementTypA
    {
      float Element[3];
    }*ElementTypA;
    
    struct _ElementTypB
    {
      float Element;
    }*ElementTypB;
    
    ElementTypA = (_ElementTypA*)getVoidPointer();
    ElementTypB = (_ElementTypB*)getVoidPointer();
    
    schreibeArray(ElementTypA);
    schreibeArray(ElementTypB);
    
    template <class _ElementTyp> void schreibeArray(_ElementTyp* ElementTyp)
    {
       _ElementTyp ArrayPuffer[100];
    
       for(int i=0; i<100; i++)
       {
         ArrayPuffer[i] = *(ElementTyp+i);
       }
       ...  
    }
    

    Ob es jetzt endlich stimmt? 😉



  • Michael E. schrieb:

    template<class T, int i>
    void foo(T bar[i])
    {
        ...
    }
    

    Das wird aber nicht funktionieren, wenn dann schon so

    template <class T, std::size_t N>
    void foo(const T (&bar)[N])
    {
        // ...
    }
    

    sqrt(-1) schrieb:

    Wie kann ich am einfachsten einen Zeiger erstellen, der auf ein Objekt z.B. vom Typ float[3] zeigt?

    ZB so

    float a[3];
    float* b = a;
    // oder
    float* c = &a[0];
    

    sqrt(-1) schrieb:

    Denn wenn ich folgendes mache...

    float blah[3];

    ... ist blah ja ein Zeiger auf ein Objekt des Types float, nicht aber float[3] - so wie ich es brauche.

    Nein, blah ist schon ein 'float[3]'. Dass der Compiler dies bei Bedarf implizit in ein 'float*' umwandeln darf, ist eine andere Sache.

    sqrt(-1) schrieb:

    Das bringt mir nichts weil ich ja einen Zeiger übergeben will und gleichzeitig den Typ (also z.B. float[3]) für das Template übermitteln muss.

    Wieso willst du einen Zeiger übergeben, wenn du den Arraytyp brauchst? Nimm oben stehende Funktion, und du hast mit 'T[N]' den Typ. Das funktioniert natürlich nicht mit dynamisch erzeugten Arrays.
    Und getVoidPointer()? Brauchst du das wirklich? Sowas deutet idR auf ein schlechtes Design.



  • groovemaster schrieb:

    sqrt(-1) schrieb:

    Wie kann ich am einfachsten einen Zeiger erstellen, der auf ein Objekt z.B. vom Typ float[3] zeigt?

    ZB so

    float a[3];
    float* b = a;
    // oder
    float* c = &a[0];
    

    Wird im gezeigten Template dann auch wirklich der ein Objekt vom Typ float[3] erkannt, oder wieder nur ein einfaches float wegen der impliziten Typumformung?

    sqrt(-1) schrieb:

    Denn wenn ich folgendes mache...

    float blah[3];

    ... ist blah ja ein Zeiger auf ein Objekt des Types float, nicht aber float[3] - so wie ich es brauche.

    Nein, blah ist schon ein 'float[3]'. Dass der Compiler dies bei Bedarf implizit in ein 'float*' umwandeln darf, ist eine andere Sache.[/quote]
    Nun, eben dies wird ja zum Problem für das was ich tun will.

    sqrt(-1) schrieb:

    Das bringt mir nichts weil ich ja einen Zeiger übergeben will und gleichzeitig den Typ (also z.B. float[3]) für das Template übermitteln muss.

    Wieso willst du einen Zeiger übergeben, wenn du den Arraytyp brauchst? Nimm oben stehende Funktion, und du hast mit 'T[N]' den Typ. Das funktioniert natürlich nicht mit dynamisch erzeugten Arrays.
    Und getVoidPointer()? Brauchst du das wirklich? Sowas deutet idR auf ein schlechtes Design.

    Nee, so eine Funktion gibt es in meinem Code nicht.
    Habe sie nur geschrieben um die Zuweisung samt Typkonvertierung zeigen zu können.

    Und ich brauche ja nicht nur den Typ, sondern den Typ und den Pointer.
    Der oben gezeigt Code scheint dies ja zu machen (zumindest nimmt der Compiler dies an).

    Die Frage von mir ist nun ob man keine schönere Alternative zu den blöden Strukturen hat, zumal ja nur ein einzigstes Array der Inhalt ist.



  • sqrt(-1) schrieb:

    Und ich brauche ja nicht nur den Typ, sondern den Typ und den Pointer.
    Der oben gezeigt Code scheint dies ja zu machen (zumindest nimmt der Compiler dies an).

    Die Frage von mir ist nun ob man keine schönere Alternative zu den blöden Strukturen hat, zumal ja nur ein einzigstes Array der Inhalt ist.

    Arraytyp und Zeiger? Kein Problem. Um es mal anhand deiner Funktion zu konkretisieren

    template <class ElementTyp, std::size_t Anzahl>
    void schreibeArray(const ElementTyp (&Elemente)[Anzahl])
    {
        ElementTyp ArrayPuffer[Anzahl];
        // wenn du einen Zeiger brauchst, dann ElementTyp* bla
    
        for (std::size_t i = 0; i != Anzahl; ++i)
        {
            ArrayPuffer[i] = Elemente[i];
        }
        //...
    }
    
    [...]
    
    // und der Aufruf
    float a[3];
    //...
    schreibeArray(a);
    


  • const ElementTyp (&Elemente)[Anzahl]

    Was passiert denn hier?
    Ich verstehe nicht was das im Cast-Operator soll.



  • Probier doch mal Type-Aliasing mit typedef, das macht die Sache uebersichtlicher:

    #include <stddef.h>
    
    typedef float Float3[3];
    typedef double Double3[3];
    
    template < class T >
    void SchreibeArray( const T* Quelle, size_t ArrayGroesse ) {
       T ArrayPuffer[100];
       for ( size_t i=0U; i < 100U && i < ArrayGroesse; ++i ) {
          ArrayPuffer[i] = Quelle[i];
       }
    }
    
    // ...
    
    void func( void ) {
       size_t   arrayGroesseN = 100U;
       Float3*  meineFloat3s  = reinterpret_cast<Float3* >( HoleVoidPtr() );
       Double3* meineDouble3s = reinterpret_cast<Double3*>( HoleVoidPtr() );
       SchreibeArray < Float3  > ( meineFloat3s , arrayGroesseN );
       SchreibeArray < Double3 > ( meineDouble3s, arrayGroesseN );
    }
    


  • sqrt(-1) schrieb:

    const ElementTyp (&Elemente)[Anzahl]

    Was passiert denn hier?

    Nichts. Das ist einfach ein Parameter.

    sqrt(-1) schrieb:

    Ich verstehe nicht was das im Cast-Operator soll.

    Cast-Operator? Was meinst du damit? Hier gibts keinen Cast-Operator.

    @Power Off
    Was soll das? Du verwirrst ihn doch nur noch mehr. Und funktionell ist dein Code auch nicht. Das einzig brauchbare ist

    void SchreibeArray( const T* Quelle, size_t ArrayGroesse )
    

    So würde man es machen, wenn auch dynamische Arrays möglich sind.



  • groovemaster schrieb:

    @Power Off
    Was soll das? Du verwirrst ihn doch nur noch mehr. Und funktionell ist dein Code auch nicht. Das einzig brauchbare ist

    void SchreibeArray( const T* Quelle, size_t ArrayGroesse )
    

    So würde man es machen, wenn auch dynamische Arrays möglich sind.

    Hmmm ... mein Vorschlag basiert auf den Hinweisen, die er auf sein Problem gegeben hat. Er hat Daten in der Form

    double x[N][3];
    float y[N][3]; 
    // usw., wobei N beliebig ist
    

    Deshalb meine Typedefs mit "Float3", "Double3", da immer ein Tupel komplett adressiert werden kann.

    Seine Funktion HoleVoidPtr() liefert die Adresse auf das naechste Array, das ich mittels reinterpret_cast<> auf jeweils einen Pointer-Typ auf Tupel-Typ X gecastet habe.

    Seinen Wunsch, template-Funktionen zu benutzen, habe ich durch die Funktion SchreibeArray<T>() abgebildet, die als Parameter den Tupel-Typ enthaelt und Pointer sowie Array-Groesse als Parameter nimmt. Da N beliebig, muss die Array-Groesse parametrisierbar sein.

    SchreibeArray<T>() ist nur eine Dummy-Implementation, da er ja sicherlich was anderes damit machen will als die Daten in temporaeres Array zu schreiben.



  • Erst einmal ein "Danke" für Euer Bemühen.

    Allerdings sehe ich nun wirklich nicht mehr durch in all den Vorschlägen.

    Was ich brauche, ist eine Template-Funktion die einen Zeiger annimmt.
    Die verschiedenen Typen sind auf die der Zeiger zeigt sind z.B.:

    float[3]
    short
    byte[4]
    ...

    Für den ersten Typ, währe also ein Element von der Größe 3*sizeof(float).

    (Die Template-Funktion muss dann noch die Byte-Offsegröße zwischen den einzelnen Elementen und die Anzahl an Elementen als Parameter annehmen.
    Dann ließt die Funktion alle Elemente entsprechend des Byte-Offsets und der Anzahl in einen Puffer und speichert diese in eine Datei.)

    Mein Problem ist es nun möglichst elegant die entsprechenden Zeiger zu kreieren und eine Template Funktion zu schreiben, die mit den verschiedenen Typen umgehen kann.
    Damit die Template-Funktion möglichst schlank wird, möchte ich gleich mit ganzen Elementen hantieren und nicht mit einzelnen primitiven Datenelementen eines Elements.

    Wenn über meine Frage noch etwas unklar ist dann bitte fragen. 😉

    Vielen Vielen Dank für Eure Hilfe!



  • Also ich habe es so wie gezeigt probiert.
    Wenn die Struktur, worauf der Zeiger zeigt, nur einen primitiven Datentyp behinhaltet, gibt es kein Problem.
    Wenn die Struktur ein Array enthält, stürzt das Programm mit dem Funktionsaufruf ab und führt nicht einmal eine Anweisung innerhalb der Template-Funktion aus.

    struct _AElement
    {
      short Element;
    }*APointer;
    
    struct _BElement
    {
      float Element[3];
    }*BPointer;
    
    APointer = (_AElement*)VoidPointer;
    LogArray(APointer, 45, 102);              // Alles Okay!
    
    BPointer = (_BElement*)VoidPointer;
    LogArray(BPointer, 55, 400);              // Absturz!
    
    template <class ElementType> DWORD LogArray(ElementType* ArrayPointer, int ArrayStride, int ArraySize)
    {
      ...
    }
    

    Bin echt ratlos.



  • Und noch einmal betreffs des Vorschlags von groovemaster:

    template <class ElementTyp, std::size_t Anzahl>
    void schreibeArray(const ElementTyp (&Elemente)[Anzahl])
    {
        ElementTyp ArrayPuffer[Anzahl];
        // wenn du einen Zeiger brauchst, dann ElementTyp* bla
    
        for (std::size_t i = 0; i != Anzahl; ++i)
        {
            ArrayPuffer[i] = Elemente[i];
        }
        //...
    }
    
    [...]
    
    // und der Aufruf
    float a[3];
    //...
    schreibeArray(a);
    

    Ich verstehe echt nicht was die Definition des Parameters für "schreibeArray(...)" da bedeutet.

    Danke für eure Hilfe!


Anmelden zum Antworten