2

I am writing own 2d matrix class. I want to design the use of this class much close to real math notation. For example I want access to element as matrix[3, 6]. But c++ didn`t give this ability, but I could access to base multidimensional array in the next way:

int matrix[2][2] = {};
int val = matrix[1][0];

So I decided to make function that return the base array. For this role the best function will be operator(). So I can access in next way: matrix()[1][0]. Ok, I started to implement it and stuck :(. Look what I have:

template <typename ValType>
class Matrix2D
{
protected:
    ValType m_data[2][2] = {};

public:
    ValType** operator()()  // <--- what type?
    {
        return m_data;
    }
}

But I received compiler error in function above

error C2440: 'return' : cannot convert from 'double [2][2]' to 'double **'

I understand error but no have idea what I must change to avoid this error? What type the function must to return?

Eliad
  • 894
  • 6
  • 20
AeroSun
  • 2,401
  • 2
  • 23
  • 46
  • 1
    "I understand error but no have idea what I must change to avoid this error?" - which means you don't. See http://stackoverflow.com/questions/4810664/how-do-i-use-arrays-in-c for more info about arrays. Basically, arrays are not pointers, and an arrays of arrays are not a pointers to pointer. – milleniumbug Apr 25 '15 at 20:38
  • Aside: a common solution to your underlying problem is to overload `()` so that you index the array with `matrix(3,6)`. Another common solution is to overload `[]` so that `matrix[3]` returns something you can apply `[]` to. Another alternative is to make a custom type to represent multidimensional indices, and then you could write `matrix[index(3,6)]`. –  Apr 25 '15 at 20:52
  • @Hurkyl Those *are* common solutions, which is why they are what I wrote as an answer to this question... – Barry Apr 25 '15 at 21:04
  • @barry you did miss one: the indexing type. – Yakk - Adam Nevraumont Apr 25 '15 at 21:26
  • @Yakk Yeah because I don't like that one. – Barry Apr 25 '15 at 23:01
  • @barry have you seen the array view "generate an index iterator that visits every element and is random access"? It can grow on you. – Yakk - Adam Nevraumont Apr 25 '15 at 23:03
  • @Yakk LInk please? I am skeptical. – Barry Apr 25 '15 at 23:12
  • @barry n3851 ts for c++1z. Should be easy to google: getting link on phone is tricky, sorry. – Yakk - Adam Nevraumont Apr 25 '15 at 23:54

3 Answers3

6

A 2D array decays to a pointer to its first "line". The following should work:

typedef ValType Line[2];

Line* operator()()
{
    return m_data;
}

You can get indexing to work in a similar way:

ValType* operator[](int line)
{
    return m_data[line];
}
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
6

Since this is tagged C++11, you should use std::array. And use the indexing operator, not the call operator:

template <typename ValType>
class Matrix2D
{
protected:
    using Row = std::array<ValType, 2>;
    std::array<Row, 2> m_data;

public:
    Row& operator[](size_t idx)
    {
        return m_data[idx];
    }
};

This way you can just write matrix[1][0] instead of having to write matrix()[1][0] (which, frankly, looks like a typo).

Additionally, if you prefer to do both indices simultaneously, you could write your call operator to simply take both:

ValueType& operator()(size_t x, size_t y) {
    return m_data[x][y];
}

That will allow you matrix(1, 0) as an alternative to matrix[1][0].

Barry
  • 286,269
  • 29
  • 621
  • 977
1

What type you will select depends on you.:) For example

ValType ( * operator()() )[2] 
{
    return m_data;
}

When an array is returned by value from a function it is implicitly converted to pointer to its frist element. You have a two-dimensional array declared like

ValType m_data[2][2] = {};

So its element in turn a one-dimensional array of type ValType[2]. Thus a pointer to such an object (the first element of the array) will be declared like

ValType ( *p )[2] = m_data;

Or

ValType ( & operator()() )[2][2] 
{
    return m_data;
}

In this case the function returns reference to the array. Functions may not return arrays themselvez but they may return references to arrays. You can use the functuon the following way

ValType( &a )[2][2] = obj(); // where obje is an object of the template class

Or you can write simpler

auto &a = obj();

Or even like

ValType ( * operator()() )[2][2] 
{
    return &m_data;
}

This use case looks similarly to the first use case except that the function returns a pointer to the whole array.


Of cource in all three cases you could use some typedefs that make the code simpler. But in any case you need to know the syntx I showed.

Take into account that there must be a semicolon after the closing brace of the class definition.:)

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • While technically well-defined, this is the sort of thing you should never write and should use typedefs to make it less obscure. –  Apr 25 '15 at 20:50
  • @Hurkyl The purpose is to show the new correct syntax for the author of the topic that he does not yet know. – Vlad from Moscow Apr 25 '15 at 20:52
  • hmmm.....on MSVS2013 it didn`t works... Where I could read more about this new future? – AeroSun Apr 25 '15 at 22:27
  • @AeroSun These member function definitions compile successfully even with MS VC++ 2010. It is evident that you simply typed incorrectly your code. – Vlad from Moscow Apr 26 '15 at 04:49
  • This looks interesting but your level of detail makes this more than obscure. Can you please give a little more detail on the background of the technique you are using here? – user1978011 Apr 26 '15 at 08:50
  • @user1978011: The first example is, for example, the same thing that [fred](http://stackoverflow.com/a/29870442/1084944) wrote, just without using the typedef to make the syntax sane. –  Apr 26 '15 at 10:42