3

I wrote a function which takes an N-dimensional std::array and a parameter pack (coordinates) equal to the number of dimensions of the input std::array. I already can estimate the size of each dimension of the std::array with a meta function and I wrote a functions counting the parameters in the pack.

I want to 1) generate a new constexpr std::array with size equal to the number of dimensions of the input std::array. 2) The array shall be initialized with the size of each dimension of the input std::array. Does someone have a tip how to fill the std::array right with C++11 only.

E.g. this code

using array3d = std::array<std::array<std::array<int, 4>, 4>, 4>;
3d_helper<array3d>(array3d(), 0,0,0);

Should generate:

constexpr std::array<int, 3> array = { 4, 4, 4 };

Here is what I have so far:

//! Static estimation of std::array container size
// Declare a generic template (which is called initially)
template <size_t dim, class Array>
struct static_size;

// specialization for std::array and first dimension
// creates a struct with a static member "value = N"
template <class T, size_t N>
struct static_size<0, std::array<T, N>> : std::integral_constant<size_t, N> {};

// specialization for std::array and dimension > 0 -> recurse down in dim
template <size_t dim, class InnerArray, size_t N>
struct static_size<dim, std::array<InnerArray, N>> : static_size<dim - 1, InnerArray> {};

template <class FIRST, class... OTHER>
size_t num_args() {
    return 1 + num_args<OTHER...>();
}

template <class FIRST>
size_t num_args() {
    return 1;
}

template <class ARRAY, class... ARGS>
struct 3d_helper {
    static glm::vec3 at_t(const ARRAY &points, ARGS... args) {
        constexpr size_t nargs = num_args<ARGS...>();
        /*
        constexpr size_t n1 = static_size<0, ARRAY>::value - 1;
        constexpr size_t n2 = static_size<1, ARRAY>::value - 1;
        */
        // ...
        using array_t = std::array<size_t, nargs>;
        // fill it somehow
    }   
};
4
  • Should it generate array3d or array<int, 3>? Commented Sep 4, 2017 at 15:27
  • array<int, 1>, array<int, 2>, array<int, 3>, ... dependent on whether the input is 1d, 2d, 3d, .. Commented Sep 4, 2017 at 15:46
  • Yes, then the example in your question is wrong. Commented Sep 4, 2017 at 15:57
  • Sorry, I updated, was a typo. I ment to generate from a 3d array a 1d containing just the size. Commented Sep 4, 2017 at 16:00

1 Answer 1

3

Based on my solution of this related question here is a way to do it

// Example program
#include <iostream>
#include <string>
#include <array>

// typedefs for certain container classes
template<class T, size_t x>
using array1D = std::array<T, x>;

template<class T, size_t x, size_t y>
using array2D = std::array<std::array<T, y>, x>;

template<class T, size_t x, size_t y, size_t z>
using array3D = std::array<std::array<std::array<T, z>, y>, x>;


template <size_t dim, typename Array>
struct size_of_dim;

// specialization for std array and first dimension
template <typename T, size_t N>
struct size_of_dim<0, std::array<T,N>> : std::integral_constant<size_t, N> {};

// specialization for std array and dimension > 0 → recurse down in dim
template <size_t dim, typename InnerArray, size_t N>
struct size_of_dim<dim, std::array<InnerArray,N>> : size_of_dim<dim-1,InnerArray> {};



template <typename Array>
struct cardinality : std::integral_constant<size_t, 0> {};

template <typename T, size_t N>
struct cardinality<std::array<T,N>> : std::integral_constant<size_t, cardinality<T>::value + 1> {};

template <typename Array>
auto constexpr cardinality_v = cardinality<Array>::value;


template <typename Array, size_t... Ns >
constexpr auto dimensions_impl(std::index_sequence<Ns...>) {
    std::array<size_t, cardinality_v<Array>> result = { size_of_dim<Ns,Array>::value... };
    return result;
}


template <typename Array>
constexpr auto dimensions() {
    return dimensions_impl<Array>(std::make_index_sequence<cardinality_v<Array>>() );
}



int main()
{
    auto test = [](auto arr){
        constexpr auto dims = dimensions<decltype(arr)>();
        for (auto d : dims)
            std::cout << d << ", ";
        std::cout << std::endl;
    };
    test(array1D<float, 1337>());
    test(array2D<float, 7357, 17>());
    test(array3D<float, 3, 4, 5>());
}

DEMO

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.