Search code examples
c++c++17variadic-templatestemplate-meta-programming

How to initialize static two dimensional array in compile-time


I made a mathematical multi-dimensional data structure, consider the following code:

template <class T, size_t ... Dims>
class ZAMultiDimTable
{
public:
    static constexpr size_t nDims = sizeof...(Dims);
    static constexpr size_t nElements = (... * Dims);
    static constexpr std::array<size_t, nDims> _indices = {Dims...};

    static size_t addIndices(size_t ind1,size_t ind2)
    {
        size_t ret = 0;
        size_t mul = 1;
        for (size_t i=0; i< nDims;++i)
        {
            ret+=mul*((ind1+ind2)%_indices[i]);
            ind1/=_indices[i];
            ind2/=_indices[i];
            mul*=_indices[i];
        }
        return ret;

    }

    friend inline const ZAMultiDimTable<T, Dims...>  operator*(const ZAMultiDimTable<T, Dims...>& l,const ZAMultiDimTable<T, Dims...>& r)
    {
        ZAMultiDimTable<T, Dims...> m;
        for(size_t i=0; i < nElements; ++i)
        {
            for (size_t j = 0; j < nElements; ++j)
            {
                m._table[addIndices(i,j)]+=l._table[i]*r._table[j];
            }
        }
        return m;
    }


private:
    std::array<T, nElements > _table;
};

the function addIndices() breaks two combined indices to the representation of multi-dimensions, and then add them.

Now, I want to create a static 2d array with size [nElements][nElements] that will replace the function addIndices(). How do I do that in an elegant way at compile time?


Solution

  • I want to create a static 2d array with size [nElements][nElements] that will replace the function "addIndices". How do I do that in an elegant way at compile time?

    Suggestion: avoid C-style arrays and use (this time) std::array instead.

    Following this suggestion, I propose

    1) make getIndices() a constexpr method

    2) define the following using (just to simplify your life in following points) or something similar (maybe with a better name)

    using arr2D = std::array<std::array<std::size_t, nElements>, nElements>;
    

    3) define the following static constexpr method

    static constexpr arr2D getIndices ()
     {
       arr2D  ret;
    
       for ( auto i = 0u ; i < nElements; ++i )
          for ( auto j = 0u ; j < nElements; ++j )
             ret[i][j] = addIndices(i, j);
    
       return ret;
     }
    

    4) add the following static constexpr member in the class (initialized as follows)

    static constexpr arr2D inds { getIndices() };
    

    Now you have your indices in a constexpr member that is initialized compile-time.