1

I am looking for a way to fill an std::array<T, N> with T being a non-default-constructible struct/class and N indeed being known at compile time, but so large, that you don't wanna hard-code all of them, such as N=256. The constructor (in my case), takes one argument, which basically equals N, and I wonder whether there is a way to get a constexpr std::array<T, 256> values without going into a copy'n'paste hell.

There would be a workaround in using unique_ptr and creating all elements upon construction of array<unique_ptr<T>, 256> dynamically. But that would mean I cannot make use of constexpr nor does it feel like the best solution.

I am providing a generalized(!) example of my problem, that I'd like to have working that way.

#include <iostream>
#include <array>
using namespace std;

struct T { int value; }; // some struct/class with non-default ctor

// a workaround-attempt
template <const size_t N> struct TT : public T { constexpr TT(): T{N} {} };

template <const size_t N>
constexpr array<T, N> makeArray() {
    return {
            TT<1>{},
            TT<2>{},
            TT<3>{},
            TT<4>{},
            TT<5>{},
            // too bad I can't place this generically
    };
}

ostream& operator<<(ostream& os, T const& t) { return os << t.value; }

int main() {
    constexpr T a = TT<4>{};
    cout << a << "\n";

    constexpr array<T, 5> v = makeArray<5>();
    for (T const& t: v) cout << " " << t.value;
    cout << "\n";

    return 0;
}

Here it should be clear, that I am currently hardcoding the makeArray<5>() method by not using N but explicitely returning an array of length 5 (in my code, that wouldn't be 5 but 256) :-).

I am currently coding in C++14 (no chance to upgrade to c++17 too soon), and I know that constexpr relaxations are improved in C++20, which isn't here either (unfortunately) :-)

How can I eliminate that and make the code look more clean in C++14?

christianparpart
  • 821
  • 9
  • 13

1 Answers1

3

Seems a works for std::make_index_sequence/std::index_sequence

template <std::size_t N, std::size_t ... Is>
constexpr array<T, N> makeArray (std::index_sequence<Is...>)
 { return { { TT<Is+1>{} ... } }; }

template <std::size_t N>
constexpr array<T, N> makeArray ()
 { return makeArray<N>(std::make_index_sequence<N>{}); }
max66
  • 65,235
  • 10
  • 71
  • 111
  • Pretty sure an index sequence by `const&` is more heavy than by value. Index sequence is an empty type. – Guillaume Racicot Mar 26 '19 at 14:07
  • @GuillaumeRacicot - really? passing an empty struct by reference is so heavy? – max66 Mar 26 '19 at 14:09
  • well, yes and no. In optimized build no. – Guillaume Racicot Mar 26 '19 at 14:16
  • But it limit using the parameter as a parameter to other constant expression: https://godbolt.org/z/Fktcpq – Guillaume Racicot Mar 26 '19 at 14:20
  • @GuillaumeRacicot - well... yes... given a decent optimizer and the fact that the argument is unused, I presume there isn't a real difference; but do you think that a (used) parameter (of empty type) is more heavy passes as reference instead of copy? Anyway: good point the second one: in this particular case isn't a problem but in more complex cases can break the const-expressness. I'll try to remember it. – max66 Mar 26 '19 at 14:41