2D Array an Methode übergeben?!



  • DKlay schrieb:

    Eine feste größe kann ich jedoch auch nicht in der Funktion definieren, da ich
    die Klasse für das lösen einer LGS verwenden möchte

    Dann würde ich die Matrix in ein eindimensionales Array stopfen.
    (Am besten noch ne Wrapper-Klasse drum, die sich dann doch zweidimenional anfühlt mit [][], aber das ist nicht dringend.)



  • float test[][3] = {{1, 2, 3}, {4, 5, 6}};
    
    void setMatrix(float* m)
    {
    	for(int zeile=0; zeile < 2; zeile++) {
    		for( int spalte=0; spalte < 2 + 1; spalte++) {
    			data[3 * zeile + spalte] = m[3 * zeile + spalte];
    		}
    	}
    }
    
    setMatrix(reinterpret_cast<float*>(test));
    


  • Wie waere es mit &test[0][0]?



  • @Mr.Long: Du meinst wohl eher

    data[3 * zeile + spalte] = m[3 * zeile + spalte];
    

    ? (beachte die 3 Änderungen!)



  • Kellerautomat schrieb:

    Wie waere es mit &test[0][0]?

    Nein funktioniert leider auch nicht.

    main.cpp:19:33: error: invalid types 'float[int]' for array subscript
         matrix1.setMatrix(&test[0][0]);
    

    Hab mich jetzt für die Möglichkeit von Mr Long entschieden mit der
    Änderung von Th69.

    Danke an dieser Stelle 👍 👍

    Hab aber noch eine Frage. Ist es nicht so das casts auf ein
    Design Fehler hindeuten?



  • Man hat bewusst Namen wie static_cast, reinterpret_cast usw. ausgewählt, da sie hässlich aussehen sollen. Ich würde dabei nicht von einem Designfehler sprechen, sondern mehr von einem schlechten Stil, aber in manchen Fällen kann man eben nicht auf Casts verzichten.
    Nur alte C-Casts solltest du nicht verwenden.


  • Mod

    Ist es nicht so das casts auf ein Design Fehler hindeuten?

    dynamic_cast deutet meistens auf einen Design-Fehler hin.
    static_cast deutet fast nie auf einen Design-Fehler hin.
    const_cast solltest du praktisch nirgends benutzen (außer du hantierst mit irgendwelchen legacy-APIs rum die nicht const-correct sind, oder du nutzt es für Trick 17).

    Man hat bewusst Namen wie static_cast, reinterpret_cast usw. ausgewählt, da sie hässlich aussehen sollen

    Das hört sich zumindest nach absolutem Quatsch an.



  • Arcoth schrieb:

    Man hat bewusst Namen wie static_cast, reinterpret_cast usw. ausgewählt, da sie hässlich aussehen sollen

    Das hört sich zumindest nach absolutem Quatsch an.

    Stimmt aber.



  • Arcoth schrieb:

    Das hört sich zumindest nach absolutem Quatsch an.

    http://www.stroustrup.com/bs_faq2.html#static-cast



  • Moderator aha.



  • Mr.Long schrieb:

    setMatrix(reinterpret_cast<float*>(test));
    

    Kellerautomat schrieb:

    Wie waere es mit &test[0][0]?

    Die ultimative Lösung ist flat_begin(test) :

    template <typename T> T *flat_begin(T &x) { return &x; }
    template <typename T, size_t N> auto flat_begin(T (&x)[N]) {
      return flat_begin(*x);
    }
    
    template <typename T> T *flat_end(T &x) { return &x + 1; }
    template <typename T, size_t N> auto flat_end(T (&x)[N]) {
      return flat_begin(x[N]);
    }
    

  • Mod

    Kellerautomat schrieb:

    Arcoth schrieb:

    Das hört sich zumindest nach absolutem Quatsch an.

    http://www.stroustrup.com/bs_faq2.html#static-cast

    Dass man tatsächlich die Hässlichkeit bedacht hatte wusste ich gar nicht, danke für den Link.

    Mr.Long schrieb:

    Moderator aha.

    😕 Was ist denn deine Einsicht?

    @flat_land:

    camper schrieb:

    template <typename T>
    constexpr auto decayed_begin(T&& c) -> decltype(std::begin(std::forward<T>(c)))
    { return std::begin(std::forward<T>(c)); }
     
    template <typename T, std::size_t M, size_t N>
    constexpr auto decayed_begin(T(&c)[M][N]) -> decltype(decayed_begin(*c))
    { return decayed_begin(*c); }
     
    template <typename T>
    constexpr auto decayed_end(T&& c) -> decltype(std::end(std::forward<T>(c)))
    { return std::end(std::forward<T>(c)); }
     
    template <typename T, std::size_t M, size_t N>
    constexpr auto decayed_end(T(&c)[M][N]) -> decltype(decayed_begin(c[M]))
    { return decayed_begin(c[M]); }
    


  • Arcoth schrieb:

    @flat_land:

    camper schrieb:

    ...
    

    Scheitert schon an dreidimensionalen Arrays, wie kann das besser sein?



  • Ausserdem ist decayed_begin ein misnomer, ich will von einem int[2][3][4] auf int* und nicht auf int[2][3]* (was decayed bedeutet) oder int*** (was deep_decayed bedeutet).



  • Du kannst mal meine Version aus demselben Thread versuchen (ungetestet ehrlich gesagt):

    asfdlol schrieb:

    template<typename T>
    T* RecBegin(T& Object)
    {
    	return &Object;
    }
    template<typename T, std::size_t n>
    typename std::remove_all_extents<T>::type* RecBegin(T(&Array)[n])
    {
    	return RecBegin(Array[0]);
    }
    
    template<typename T>
    T* RecEnd(T& Object)
    {
    	return &Object;
    }
    template<typename T, std::size_t n>
    typename std::remove_all_extents<T>::type* RecEnd(T(&Array)[n])
    {
    	return RecBegin(Array[n]);
    }
    

    Edit:
    Achso, du hast gar nicht nach einer Lösung gefragt. Sorry. Bisschen durch den Wind heute. 🙄



  • asfdlol schrieb:

    Du kannst mal meine Version aus demselben Thread versuchen (ungetestet ehrlich gesagt):

    Abgesehen von dem Off-By-One error in RecEnd scheint die zu stimmen.

    Gute Idee mit remove_all_extents, das macht den Code C++11-konform.

    Ich denke der Gewinner ist

    template <typename T> constexpr T *flat_begin(T &x) { return &x; }
    template <typename T, size_t N>
    constexpr typename std::remove_all_extents<T>::type *flat_begin(T (&x)[N]) {
      return flat_begin(*x);
    }
    
    template <typename T> T *flat_end(T &x) { return &x + 1; }
    template <typename T, size_t N>
    constexpr typename std::remove_all_extents<T>::type *flat_end(T (&x)[N]) {
      return flat_begin(x[N]);
    }
    

  • Mod

    @flat: Ok

    #include <iterator>
    #include <type_traits>
    
    #define AUTO_RETURN(...) -> decltype(__VA_ARGS__) {return (__VA_ARGS__);}
    
    template <typename T>
    constexpr auto decayed_begin(T&& c)
    AUTO_RETURN(std::begin(std::forward<T>(c)))
    
    template <typename T>
    constexpr auto decayed_end(T&& c)
    AUTO_RETURN(std::end(std::forward<T>(c)))
    
    template <typename T, typename std::enable_if<std::is_array<T>::value, std::size_t>::type N>
    constexpr typename std::remove_all_extents<T>::type* decayed_begin(T(&c)[N])
    {
    	return decayed_begin(*c);
    }
    
    template <typename T, std::size_t N>
    constexpr auto decayed_end(T(&c)[N])
    AUTO_RETURN( decayed_begin(c[N]) )
    

    ?

    Edit: Zu spät...



  • Arcoth schrieb:

    @flat: Ok

    Könntest du wenigstens deinen Code mal testen? ^Und meinen Namen richtig schreiben? Der ist weder flat_land noch flat.^

    const int arr[2][3][4][5]={};
    assert(flat_end(arr)-flat_begin(arr) == 2*3*4*5);
    std::vector<int> v[2] = {{ 1, 2, 3 }, { 4, 5, 6 }};
    auto i = flat_begin(v), e = flat_end(v);
    assert(e - i == 2);
    int x = 0;
    assert(flat_begin(x) + 1 == flat_end(x));
    

    AUTO_RETURN ist übrigens voll out.

    Ausserdem habe ich erörtert, wieso decayed_* die falsche Bezeichnung ist.

    Das constexpr kannst du übrigens auch streichen, das funktioniert aus irgendwelchen Gründen nicht. Wahrscheinlich hat camper deshalb die Anzahl Dimensionen hardgecoded.


  • Mod

    flatland schrieb:

    Mr.Long schrieb:

    setMatrix(reinterpret_cast<float*>(test));
    

    Kellerautomat schrieb:

    Wie waere es mit &test[0][0]?

    Die ultimative Lösung ist flat_begin(test) :

    template <typename T> T *flat_begin(T &x) { return &x; }
    template <typename T, size_t N> auto flat_begin(T (&x)[N]) {
      return flat_begin(*x);
    }
    
    template <typename T> T *flat_end(T &x) { return &x + 1; }
    template <typename T, size_t N> auto flat_end(T (&x)[N]) {
      return flat_begin(x[N]);
    }
    

    Wenn das das Problem ist, das du lösen wolltest...

    flatland schrieb:

    Arcoth schrieb:

    @flat_land:

    camper schrieb:

    ...
    

    Scheitert schon an dreidimensionalen Arrays, wie kann das besser sein?

    Der Code ist offenbar schlecht, weil zu subtil. Im Übrigen hast du unrecht.

    flatland schrieb:

    Ausserdem ist decayed_begin ein misnomer, ich will von einem int[2][3][4] auf int* und nicht auf int[2][3]* (was decayed bedeutet) oder int*** (was deep_decayed bedeutet).

    und das heisst jetzt was?


  • Mod

    Könntest du wenigstens deinen Code mal testen?

    Das habe ich:

    #include <iterator>
    #include <type_traits>
    
    #define AUTO_RETURN(...) -> decltype(__VA_ARGS__) {return (__VA_ARGS__);}
    
    template <typename T>
    constexpr auto decayed_begin(T&& c)
    AUTO_RETURN(std::begin(std::forward<T>(c)))
    
    template <typename T>
    constexpr auto decayed_end(T&& c)
    AUTO_RETURN(std::end(std::forward<T>(c)))
    
    template <typename T, typename std::enable_if<std::is_array<T>::value, std::size_t>::type N>
    constexpr typename std::remove_all_extents<T>::type* decayed_begin(T(&c)[N])
    {
    	return decayed_begin(*c);
    }
    
    template <typename T, std::size_t N>
    constexpr auto decayed_end(T(&c)[N])
    AUTO_RETURN( decayed_begin(c[N]) )
    
    #include <iostream>
    
    int main()
    {
    	int arr[4][3][2] { 2, 3, 5, 7, 11,
    	                   13, 17, 19, 23, 29,
    	                   31, 37, 41, 43, 47,
    	                   53, 59, 61, 67, 71,
    	                   73, 79, 83, 89 };
    
    	std::copy( decayed_begin(arr), decayed_end(arr), std::ostream_iterator<int>{std::cout, " "} );
    }
    

    Allerdings gibt es hier einen recht subtilen Ambiguitäts-Bug, der durch dein Beispiel hervorgehoben und durch

    template <typename T, typename std::enable_if<std::is_array<T>::value, std::size_t>::type N>
    constexpr auto decayed_end(T(&c)[N])
    AUTO_RETURN( decayed_begin(c[N]) )
    

    gelöst wird.

    Ist dein flat_begin aus der "Gewinnerlösung" nicht völliger Quatsch? Funktioniert bei einem Container doch gar nicht?

    Jetzt funktioniert auch dein Testcode, mit Ausnahme der letzten beiden Zeilen - die sind aber auch nicht sinnvoll. Eine Variable ist keine Range.

    Ausserdem habe ich erörtert, wieso decayed_* die falsche Bezeichnung ist.

    Ist mir egal.

    Und meinen Namen richtig schreiben?

    Der ist mir noch egaler.

    Übrigens ist es out andere Leute penibel zu korrigieren. Es geht um Ideen und nicht um Namen.


Anmelden zum Antworten