Question

I've been coding in C# for quite a while now and have switched back to C++ recently. Basically what I'm trying to do in terms of C# is:

static void Main(string[] args)
{
    int[,] mat =  { {1, 2, 3},
                    {4, 5, 6}, 
                    {7, 8, 9} };

    SomeClass<int> s1 = new SomeClass<int>(mat);
    int[,] result = s1.doSomething();

    int[,] mat2 = { { 1,  2,  3,  4},
                    { 5,  6,  7,  8}, 
                    { 9, 10, 11, 12},
                    {13, 14, 15, 16} };

    SomeClass<int> s2 = new SomeClass<int>(mat);
    int[,] result2 = s2.doSomething();  
}

public class SomeClass<T>
{
    T[,] data;

    public SomeClass(T[,] arg)
    {
        data = arg;
    }

    //member method of SomeClass
    public T[,] doSomething()
    {
        return data;
    }
}

Actually this shouldn't be to hard at the first glance but unfortunately C++ is a bit more picky when it comes to arrays of anonymous size. There are some workarounds of course:

  1. Use T** I consider this solution quite hacky, T** is not really the same as T[][] and you can pass messy things that might result into runtime errors rather than compiler errors. Then there is the initialization issue.

  2. T[][] Would be nice but unlike C# C++ doesn't allow the declaration of 2D arrays of anonymous size in both dimensions (T[][3]) would be possible but none of the two dimensions should be fixed. I need to be able to work with 3x3 matrices at one point in the program and lets say with 4x4 or 5x5 matrices at another point.

  3. So I did some research and found another approach using templates and non-type parameters. So my idea is to do sth. like this:

    template<typename T, size_t S> Someclass<T, S>::Someclass(T[S][S]) { .. }

    template<typename T, size_t S> T[S][S] Someclass<T, S>:doSomething() { .. }

.. which unfortunately doesn't seem to work that way. This approach has even one more advantage it implicitly adds a constraint that the first and the second dimension of the array must be of the same size.

I'm using Visual Studio 2010's compiler so I might not be able to use the features of the latest C++ compilers.

So my question: Is there a way to achive what the 3rd idea implies?

  1. Pass and return 2D Arrays of anonymous size...
  2. ...with the constraint that the first and second dimension must be of the same size.

** UPDATE ** I've been having a hard time getting the proposed solutions to run under Visual Studio. I'll give it another try but wanted to keep you posted: I created a small test Project - this is how far I got:

//SomeClass.h
#ifndef SOMECLASS_H //<- line 1
#define SOMECLASS_H

#include "SquareMatrixA.h"
#include "SquareMatrixB.h"

template<typename T, size_t S>
class SomeClass
{
    private: 
        SquareMatrixA<T> matA;
        SquareMatrixB<T, S> matB;

    public:
        SomeClass(SquareMatrixA<T> arg);
        SomeClass(SquareMatrixB<T, S> arg);
        virtual ~SomeClass(void);

        SquareMatrixA<T> doSomethingA();
        SquareMatrixB<T, S> doSomethingB();
};

#endif


//SomeClass.cpp //<-- line 1
#include "SomeClass.h"

template<typename T, size_t S>
SomeClass<T, S>::SomeClass(SquareMatrixA<T> arg) { matA = arg; }

template<typename T, size_t S>
SomeClass<T, S>::SomeClass(SquareMatrixB<T, S> arg) { matB = arg; }

template<typename T, size_t S> 
SomeClass<T, S>::~SomeClass(){}

template<typename T, size_t S> 
SquareMatrixA<T> SomeClass<T, S>::doSomethingA() { return matA; }

template<typename T, size_t S>
SquareMatrixB<T, S> SomeClass<T, S>::doSomethingB() { return matB; }


//SquareMatrixA.h (inline)
#ifndef SQUAREMATRIXA_H //<- line 1
#define SQUAREMATRIXA_H

#include <vector>
#include <utility>

template<typename T>
class SquareMatrixA
{
    protected:
        std::vector<T> data;
        size_t size;

    public:
        SquareMatrixA(size_t size) : data(size * size), size(size) { }
        T& operator()(size_t i, size_t j) { return data.at(i * size + j); }
        T const& operator() const(size_t i, size_t j) { return data.at(i * size + j); }
        T& operator[](std::pair<size_t, size_t> p) { return data.at(p.first * size + p.second); }
        T const& operator[](std::pair<size_t, size_t> p) const { return data.at(p.first * size + p.second); }
};

#endif


//SquareMatrixB.h
#ifndef SQUAREMATRIXB_H // <-- line 
#define SQUAREMATRIXB_H

template<typename T, size_t S> 
class SquareMatrixB
{
    typedef T (&oneDimRefT)[S]; 

    private:
        T matrix[S][S];

    public:
        const size_t Size;
        SquareMatrixB(size_t sizeA) : Size(sizeA) { }
        oneDimRefT operator[](size_t i) { return matrix[i]; }
};

#endif

Visual Studio shows the following errors (sorry for the partially german output but seemingly Visual Studios language cant changed to english except by installing a native english Version:

Fehler  1   error C2143: Syntaxfehler: Es fehlt ';' vor 'const' squarematrixa.h 17  1   MatrixTest2
Fehler  2   error C2365: "SquareMatrixA<T>::operator ()": Erneute Definition; vorherige Definition war "Memberfunktion".    squarematrixa.h 17  1   MatrixTest2
Fehler  3   error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.   squarematrixa.h 17  1   MatrixTest2
Fehler  4   error C2226: Syntaxfehler: Typ 'size_t' nicht erwartet  squarematrixa.h 17  1   MatrixTest2
Fehler  5   error C2334: Unerwartete(s) Token vor '{'; sichtbarer Funktionstext wird übersprungen   squarematrixa.h 17  1   MatrixTest2
Was it helpful?

Solution 2

Your template idea is surely doable. The interesting part is the squareMatrixT class declaration with the typedef. The defined type is a reference to a one-dimensional array of the specified size. That's what the index operator returns (a plain old array, well, as ref). The rest of the code is just proof of concept clutter (objects of this type can be passed as reference or as value, all data is contained in the object).

#include<iostream>
using namespace std;

const size_t MSIZE = 3;

template<typename T, size_t S> class squareMatrixT
{
    T matrix[S][S];
    typedef T (&oneDimRefT)[S];   // the interesting part

    public:

    const size_t size = S;
    oneDimRefT operator[](size_t i) { return matrix[i]; }
};

typedef squareMatrixT<int,MSIZE> sqm3T;   // convenience and brevity

void init(sqm3T &sqm3)
{
    for(int i=0; i<sqm3.size; i++)
    {
        for(int j=0; j<sqm3.size; j++)
        {
            sqm3[i][j] = i*sqm3.size + j;
        }
    }   
}

void  print(sqm3T sqm3)
{
    for(int i=0; i<sqm3.size; i++)
    {
        for(int j=0; j<sqm3.size; j++)
        {
            cout << sqm3[i][j] << ' ';
        }
        cout << endl;
    }   
}

int main(void)
{
    sqm3T sqm33main;
    init(sqm33main);   // by ref
    print(sqm33main);  // by val
    return 0;
}

OTHER TIPS

MSDN suggests that std::tr1::array is available. This eases usage of C-style arrays by wrapping them inside a class. This way not only simplifies the syntax (at least to me), but most importantly allows assigning, copying and therefore also returning them from functions:

template<typename T, size_t S>
Someclass<T, S>::Someclass(std::tr1::array<S, std::tr1::array<S, T> > const&);

template<typename T, size_t S>
std::tr1::array<S, std::tr1::array<S, T> > Someclass<T, S>:doSomething();

This is very close to what you wished, but differs from the C# solution in that it requires the size of the matrices to be known at compile time.

If you wish to allow for matrices whose sizes are known only at runtime, you will need to provide your own container (or find a 3rd party library providing a class for dynamic square matrices), possibly based on std::vector along the lines of the following:

template<typename T>
class matrix {
    std::vector<T> data;
    size_t size;

public:
    matrix(size_t size) : data(size * size), size(size) { }
    T& operator()(size_t i, size_t j) { return data.at(i * size + j); }
    T const& operator() const(size_t i, size_t j) { return data.at(i * size + j); }
    T& operator[](std::pair<size_t, size_t> p) { return data.at(p.first * size + p.second); }
    T const& operator[](std::pair<size_t, size_t> p) const { return data.at(p.first * size + p.second); }
};

Note, that overloading the array subscript operator to take more than one argument is sadly not allowed in c++.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top