5

I need to write a wrapper class that provides "get" methods for the fields of a data class. However, I don't know the syntax to write a "getter" to return a 2D array. For example:

#include <iostream>

class Data {
public:
    double array[2][2];
};

class Wrapper {
private:
    Data* dataptr;
public:
    Wrapper(Data* data) : dataptr(data) {}

    // compile error: "cannot convert ‘double (*)[2]’ to ‘double**’ in return"
    double** getarray() { return dataptr->array; } 

    // compile error: "‘getarray’ declared as function returning an array"
    //double* getarray()[2] { return dataptr->array; } 

    // this works, but what is auto resolved to?
    //auto getarray() { return dataptr->array; } 
};

int main() {

    Data d;
    d.array[0][0] = 1;
    d.array[0][1] = 2;
    d.array[1][0] = 3;
    d.array[1][1] = 4;

    Wrapper w(&d);
    auto arr = w.getarray();
    return 0;
}

I know that it is possible as I set the method return type to auto and it compiles and runs as expected. But I don't know how to write the method with an explicit return type.

In my real world example, I cannot modify the Data class so switching to using std::vector is not an option.

David Hadley
  • 184
  • 2
  • 8
  • 1
    Side note about the dupe: I'm much more satisfied with the answers here than in the duplicate. Both answers here use modern C++ whilst the answers in the dupe all rely on pre-C++11. (as of this time of posting). – TrebledJ Jan 10 '19 at 15:01

2 Answers2

5

The error message tells you the type! The tricky part is the syntax:

double (*getarray())[2] { return dataptr->array; } 

In other words, you almost had it, but you need to bind that * a bit tighter using parentheses.

You can avoid the decay of the outermost dimension:

double (&getarray())[2][2] { return dataptr->array; }

Or you can put this type into an alias to avoid the mess.

Or you can use auto, or switch to std::array to make things easier :P

#include <iostream>
#include <array>

class Data {
public:
    using ArrayType = std::array<std::array<double, 2>, 2>;
    ArrayType array;
};

class Wrapper {
private:
    Data* dataptr;
public:
    Wrapper(Data* data) : dataptr(data) {}

    Data::ArrayType& getarray() { return dataptr->array; } 
};

int main() {

    Data d;
    d.array[0][0] = 1;
    d.array[0][1] = 2;
    d.array[1][0] = 3;
    d.array[1][1] = 4;

    Wrapper w(&d);
    auto arr = w.getarray();
    return 0;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
4

Simpler would be decltype(auto) (since C++14)

decltype(auto) getarray() { return dataptr->array; }

then decltype (since C++11) (member should be before the method declaration though):

auto getarray() -> decltype((dataptr->array)) { return dataptr->array; }

then typedef way:

using double2D = double[2][2];

double2D& getarray() { return dataptr->array; }

as regular syntax is very ugly way:

double (&getarray())[2][2] { return dataptr->array; }

Using std::array<std::array<double, 2>, 2> (since C++11) would have more natural syntax.

Jarod42
  • 203,559
  • 14
  • 181
  • 302