Home How to handle matrices of different dimensions using templates?
Reply: 1

How to handle matrices of different dimensions using templates?

Cyril C.
1#
Cyril C. Published in 2017-12-07 13:49:53Z

I would like to achieve the conversion of a matrix to a string, regardless of its size(s), type or dimension(s). Using templates, I've managed to make it work by defining one template for each "sort" of matrix I need.

Template for arrays:

template < typename NUM, std::size_t SIZE >
std::string to_string( const std::array< NUM, SIZE > &arr ) {

    std::string buf;
    for ( uint32_t i = 0; i < SIZE; i++ )
        buf += std::to_string( arr[i] ) + " ";

    return buf;
}

Template for 2-dimensionnal matrices:

template < typename NUM, std::size_t INNER_SIZE, std::size_t OUTER_SIZE >
std::string to_string( const std::array< std::array<NUM, INNER_SIZE>, OUTER_SIZE > &arr ) {

    std::string buf;

    for ( uint32_t i = 0; i < OUTER_SIZE; i++ ) {
        for ( uint32_t j = 0; j < INNER_SIZE; j++ )
            buf += std::to_string( arr[i][j] ) + " ";
    }

    return buf;
}

However, I'd like to make the solution more 'elegant', by only having a generic template that could handle matrices regardless of their dimensions. Is there any way to do that ?

max66
2#
max66 Reply to 2017-12-07 21:29:56Z

First of all: I strongly suggest to avoid to give your functions the same name of a standard function. So, in the following example, I've renamed fooString() your function to avoid the risk of a clash with std::to_string.

Second: as observed by Bob__, if you replace the inner loop with a call to to_string(arr[i]) (fooString(arr[i]), with my renaming), you resolve recursively the problem of the multidimensional (for every dimension) array.

Third: I suggest to write a ground case that get the std::to_string() for a single value (where T is the base (not array) type, like int, float, etc.)

template <typename T>
std::string fooString (T const & val)
 { return std::to_string(val); }

and the recursive case become

template <typename T, std::size_t Dim>
std::string fooString (std::array<T, Dim> const & arr)
 {
    std::string buf;

    for ( auto const & elem : arr )
        buf += fooString( elem ) + " ";

    return buf;
}

With a ground case that treat a base type you have one more level of indirection (so performances are, presumably, a little worse) but the logic of array management is only in one function and not almost equal in two (less error prone maintaining the code).

The following is a full working C++11 example

#include <array>
#include <string>
#include <iostream>

template <typename T>
std::string fooString (T const & val)
 { return std::to_string(val); }

template <typename T, std::size_t Dim>
std::string fooString (std::array<T, Dim> const & arr)
 {
    std::string buf;

    for ( auto const & elem : arr )
        buf += fooString( elem ) + " ";

    return buf;
}

int main()
 {
   std::array<std::array<std::array<int, 2U>, 3U>, 4U> a3dim
    {{ {{ {{  2,  3 }}, {{  5,  7 }}, {{ 11, 13 }} }},
       {{ {{ 17, 19 }}, {{ 23, 29 }}, {{ 31, 37 }} }},
       {{ {{ 41, 43 }}, {{ 47, 53 }}, {{ 59, 61 }} }},
       {{ {{ 67, 71 }}, {{ 73, 79 }}, {{ 83, 89 }} }} }};

   std::cout << fooString(a3dim) << std::endl;
 }
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.304054 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO