-1

What begun as a revision of some aspects of C++ has become a sketch of something that could be useful for me. The idea is to use a single array as a double array where indexing is transparent for the user.

class matrice {

    private:
        int* data;
        int rows, cols;
    public:
        matrice(int _rows, int _cols) : rows(_rows), cols(_cols) { data = new int[_rows*_cols]; std::cout << "matrice ctr" << std::endl;}
        // hardcoded 2x2 matrix
        void set_value() { data[0] = 1; data[1] = 0; data[3] = 1; data[4] = 0;}
        int get_rows() { return rows;}
        int get_cols() { return cols;}

        class proxy {
            private:
                int i;
                int j;
                const int rows; // it is constant so we don't mess up with the size of the matrix
                int *proxy_data;
            public:
                proxy(int* _proxy_data, int _i, const int& _rows) : proxy_data(_proxy_data), i(_i), rows(_rows) { }
                int operator[] (int _j) { j = _j; std::cout << "proxy:\n\tj = " << j << " " << proxy_data[j] << std::endl; return proxy_data[i*rows + j];}
        };

        proxy operator[] (int i) { std::cout << "matrice:\n\ti = " << i << std::endl; return proxy(data, i, rows); } 

};

int main()
{
    int rows = 2;
    int cols = 2;

    matrice matp(rows, cols);
    matp.set_value();
    matp[0][0] = 2;
    for (int i = 0;i < rows;i++) {
        for (int j = 0;j < cols;j++) {
            std::cout << "matp[" << i << "][" << j << "] = " << matp[i][j] << std::endl;
        }
    }
}

So far I can access the data in the array however, I want to assign values to it i.e.: matp[0][0] = 2;

How could I do it ?

rbw
  • 187
  • 5
  • Please read https://isocpp.org/wiki/faq/operator-overloading#matrix-array-of-array – Sneftel Nov 14 '18 at 18:15
  • @Sneftel It says for a matrix. If I want to work with large matrices then this interface is fine. Furthermore, [it has been shown](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster) that in general 1D is better than 2D. – rbw Nov 14 '18 at 18:59
  • 1
    I think you misunderstood that FAQ. It's not about 1D versus 2D, it's about [][] not being a good use of operator overloading. – Sneftel Nov 15 '18 at 06:21

1 Answers1

1
int& operator[] (int j)const&&

Also delets int j member it is pointless.

int& operator[] (int j) const&& {
  std::cout << "proxy:\n\tj = " << j << " " << proxy_data[j] << std::endl; 
  return proxy_data[i*rows + j];}
};

or better:

    template<class X>
    class proxy {
        private:
            X *proxy_data;
        public:
            proxy(X* _proxy_data, std::size_t i, std::size_t stride) : proxy_data(_proxy_data+i*stride) { }
            X& operator[] (std::size_t j) const&& { return proxy_data[j]; }
    };

use proxy<int> and proxy<const int> as the return value from [] and [] const.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • This would be correct, but I'm pretty sure you don't want that `const` to be there. If you wanted a `const` overload, it would probably return by `const` reference, or by value. – Mooing Duck Nov 14 '18 at 18:21
  • @mooing what, you are going to modify the state of the proxy in `[]` What kind of mad duck are you?! – Yakk - Adam Nevraumont Nov 14 '18 at 18:22
  • 1
    Rather the opposite. I think a `const` overload should _prevent_ the user from modifying the underlying data. Your code allows users to modify the underlying data, even with a `const proxy` object. `const` should be used to demonstrate logical const-ness, not technical constness. – Mooing Duck Nov 14 '18 at 18:23
  • @mooing Bad idea with view types. A pointer to const and a const pointer are not the same thing, and a const proxy is a const pointer, not a pointer to const. I'd template the target type and make it const or not instead. – Yakk - Adam Nevraumont Nov 14 '18 at 19:48
  • Ironically, that's exactly the concept I'm trying to preserve. A `const Matrixe` should return a `const proxy` which should return a `const int`. A mutable `Matrixe` should return a mutable `proxy`, which should return a `int&`. Your answer could lead to a `const Matrixe` return a `const proxy`, which returns a mutable `int&`. I understand what you're saying about `const T*` vs `T* const`, but my point is you've coded `T* const`, which, though technically accurate, is a dangerous tool. This is why every stl class has a separate `iterator` and a `const_iterator`. – Mooing Duck Nov 14 '18 at 21:13
  • 1
    @mooing no `T*const` is not "dangerous" it is how the language works. I've gone down the path of "make the reference type const for const access" and it falls apart; value types being const for const access is correct, but it is wrong, error prone and bad for reference/pointer types. Make types as close to regular as you can. A `const_iterator` **is not and should not be** a `iterator const`. proxy is not a value type, `const_proxy` should be a different type than `proxy`. – Yakk - Adam Nevraumont Nov 14 '18 at 22:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/183665/discussion-between-mooing-duck-and-yakk-adam-nevraumont). – Mooing Duck Nov 15 '18 at 00:47