'Passing and Returning a 2D array of unknown size in C++

I want to pass and return a 2D array of unknown size but I donot know how to do it. I know how to only return array of unknown size only (array of pointers). I know how to pass array of unknown size(templates) , but passing and returning a 2D array of unknown size at the same time is not working for me. I have the following code

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
int** FooTakes2D_ArrayRef_to_Print(Value_t (&array2d)[FirstDim][SecondDim]) 
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
} 
 
int main() 

{ 
   
    double arr_d[][3]= { {1,2,3},  {4,5,6} }; 
    int** arr=FooTakes2D_ArrayRef_to_Print(arr_d);

 
return 0; 

}


Solution 1:[1]

The problem is that the return type of your function is int** but you are returning array2d which decays to a double (*)[3] due to type decay. Thus, there is a mismatch in the specified return type of the function and the type you're actually returning.

To solve this you can either use std::vector or use the placeholder type auto as shown below:

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
//auto used here
auto FooTakes2D_ArrayRef_to_Print(Value_t (&array2d)[FirstDim][SecondDim]) -> decltype(array2d)
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}
int main() 
{ 
   
    double arr_d[][3]= { {1,2,3},  {4,5,6} }; 
    //auto used here
    auto arr=FooTakes2D_ArrayRef_to_Print(arr_d);
}

Working demo

Solution 2:[2]

For starters you declared an array of doubles:

double arr_d[][3]= { {1,2,3},  {4,5,6} }; 

but then are using the specifier int in the function declaration and in this statement.

int** arr=FooTakes2D_ArrayRef_to_Print(arr_d);

Pay attention to that array designators used in expressions with rare exceptions are implicitly converted to pointers to their first elements. So for example the array arr_d can be implicitly converted to a pointer of the type double ( * )[3].

The function can look like:

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
Value_t ( & FooTakes2D_ArrayRef_to_Print(Value_t (&array2d)[FirstDim][SecondDim]) )[FirstDim][SecondDim]
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

That is it can return a reference to the source array.

Or like for example

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
Value_t ( * FooTakes2D_ArrayRef_to_Print(Value_t (&array2d)[FirstDim][SecondDim]) )[SecondDim]
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

returning a pointer to the first element of the array.

In the both cases you can declare a pointer in main like

double (* arr )[3] = FooTakes2D_ArrayRef_to_Print(arr_d);

Here is a demonstration program

#include <iostream>

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
Value_t ( & FooTakes2D_ArrayRef_to_Print(Value_t (&array2d)[FirstDim][SecondDim]) )[FirstDim][SecondDim]
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
Value_t ( * FooTakes2D_ArrayRef_to_Print2(Value_t (&array2d)[FirstDim][SecondDim]) )[SecondDim]
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

int main()
{
    double arr_d[][3]= { {1,2,3},  {4,5,6} }; 
    double (* arr )[3] = FooTakes2D_ArrayRef_to_Print(arr_d);
    double (* arr2 )[3] = FooTakes2D_ArrayRef_to_Print2(arr_d);
}`

The program output is:

1 2 3 
4 5 6 
1 2 3 
4 5 6 `

Or you could use an alias for the reference of the two-dimensional array the following way:

#include <iostream>

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
using Arr2D = Value_t ( & )[FirstDim][SecondDim];

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
Arr2D<Value_t, FirstDim, SecondDim>
FooTakes2D_ArrayRef_to_Print(Arr2D<Value_t, FirstDim, SecondDim> array2d )
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

template<typename Value_t, size_t FirstDim, size_t SecondDim> 
auto FooTakes2D_ArrayRef_to_Print2(Arr2D<Value_t, FirstDim, SecondDim> array2d )
{ 
    for(size_t i=0; i<FirstDim; ++i) 
    { 
        for(size_t j=0; j<SecondDim; ++j) 
        { 
            std::cout<<array2d[i][j]<<' '; 
        } 
        std::cout<<"\n"; 
    } 
 
 return array2d; 
}

int main()
{
    double arr_d[][3]= { {1,2,3},  {4,5,6} }; 
    double (* arr )[3] = FooTakes2D_ArrayRef_to_Print(arr_d);
    double (* arr2 )[3] = FooTakes2D_ArrayRef_to_Print2(arr_d);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 halfer