c++arraysstdarray

How can I construct an std::array filled with some uniform value?


std::array can be constructed (at compile time with newer C++ versions) with specific values, e.g.

std::array a{1, 4, 9};

however - it does not have a constructor, or a standard-library named constructor idiom, taking a single value and replicating it. i.e. we don't have:

std::array<int, 3> a{11};
// a == std::array<int, 3>{11, 11, 11};

How can we, therefore, construct an array given just the value to repeat?

Edit: I'm looking for a solution which would work even for element types which are not default constructible; so, a solution going through default-constructing the array, then filling it, is not what I'm after - despite the fact that this will work for the case of int (like in the example).


Solution

  • We can write an appropriate named constructor idiom to achieve this. Then, your example definition would look like:

    auto a = array_repeat<3>(11);
    // a == std::array<int, 3>{11, 11, 11};
    

    The implementation is a bit clunky, however, as we need to use the "indices trick" that takes a lot of boilerplate in C++11, so let's assume C++14:

    namespace detail {
    
    template<size_t, class T>
    constexpr T&& identity(T&& x) { return std::forward<T>(x); }
    
    template<class T, size_t... Indices>
    constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
    {
        return std::experimental::make_array(identity<Indices>(x)...);
    }
    
    } // end detail
    
    template<size_t N, class T>
    constexpr auto array_repeat(T&& x)
    {
        return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
    }
    

    See this working on GodBolt.

    If you can compile your code C++20, you can drop the dependency on make_array and write:

    namespace detail {
    
    template<size_t, class T>
    constexpr T&& identity(T&& x) { return std::forward<T>(x); }
    
    template<class T, size_t... Indices>
    constexpr auto array_repeat_impl(T&& x, std::index_sequence<Indices...>)
    {
        return std::array{identity<Indices>(x)...};
    }
    
    } // end detail
    
    template<size_t N, class T>
    constexpr auto array_repeat(T&& x)
    {
        return detail::array_repeat_impl(std::forward<T>(x), std::make_index_sequence<N>());
    }
    

    GodBolt

    Notes: