define an array based on constexpr array transform

Viewed 157

Is there a way to define a new array by transforming from an existing array, where both arrays are compile time known constexpr arrays, like this:

constexpr array<string_view, 3> arr{"foo", "bar", "alpha"};
for (auto o : arr) {
  std::cout << ' ' << o;
}
std::cout << '\n';

constexpr array<size_t, arr.size()> arr2{0};
for (auto o : arr2) {
  std::cout << ' ' << o;
}
std::cout << '\n';

std::transform(arr.begin(), arr.end(), arr2.begin(),
               [](auto e) { return e.size(); });

// arr2: {3, 3, 5}
static_assert(arr2[2] == 3);

This code fails to compile even though in c++20 it added constexpr version of std::transform, error:

In file included from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/algorithm:62,
             from <source>:1:
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_algo.h: In instantiation of 'constexpr _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation) [with _IIter = const std::basic_string_view<char>*; _OIter = const long unsigned int*; _UnaryOperation = main()::<lambda(auto:16)>]':
<source>:29:50:   required from here
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_algo.h:4296:19: error: assignment of read-only location '* __result'
4296 |         *__result = __unary_op(*__first);
  |         ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
<source>: In function 'int main()':
<source>:31:25: error: static assertion failed
31 |   static_assert(arr2[2] == 3);
1 Answers

You can write a function that returns an array and use that to initialise the constexpr variable. Example:

constexpr auto make_the_array = [=] {
    std::array<std::size_t, arr.size()> temp_arr{0};
    auto get_size = [](auto e) { return e.size(); };
    std::transform(arr.begin(), arr.end(),
         temp_arr.begin(), get_size);
    return temp_arr;
};
constexpr auto arr2 = make_the_array();
Related