47

I need to initialize all elements of a std::array with a constant value, like it can be done with std::vector.

#include <vector>
#include <array>

int main()
{
  std::vector<int> v(10, 7);    // OK
  std::array<int, 10> a(7);     // does not compile, pretty frustrating
}

Is there a way to do this elegantly?

Right now I'm using this:

std::array<int, 10> a;
for (auto & v : a)
  v = 7;

but I'd like to avoid using explicit code for the initialisation.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • 2
    Related to [Why does std::array not have an constructor that takes a value for the array to be filled with?](https://stackoverflow.com/questions/17923683/why-does-stdarray-not-have-an-constructor-that-takes-a-value-for-the-array-to) – Jarod42 Sep 04 '19 at 22:27

8 Answers8

36

With std::index_sequence, you might do:

namespace detail
{
    template <typename T, std::size_t ... Is>
    constexpr std::array<T, sizeof...(Is)>
    create_array(T value, std::index_sequence<Is...>)
    {
        // cast Is to void to remove the warning: unused value
        return {{(static_cast<void>(Is), value)...}};
    }
}

template <std::size_t N, typename T>
constexpr std::array<T, N> create_array(const T& value)
{
    return detail::create_array(value, std::make_index_sequence<N>());
}

With usage

auto a = create_array<10 /*, int*/>(7); // auto is std::array<int, 10>

Which, contrary to std::fill solution, handle non default constructible types.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
31

Alas not; std::array supports aggregate initialisation but that's not enough here.

Fortunately you can use std::fill, or even std::array<T,N>::fill, which, from C++20 is elegant as the latter becomes constexpr.

Reference: https://en.cppreference.com/w/cpp/container/array/fill

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
22

You can do as following

std::array<int, 10> a; 
a.fill(2/*or any other value*/);

Or use std::fill from algorithms header file. To include algorithms header file use

#include <algorithm>
h4ckthepl4net
  • 391
  • 1
  • 12
  • 1
    Thanks for taking the time to write out the actual code. This is something I don't do often enough: Stack Overflow works best when there are multiple answers to choose from. – Bathsheba Sep 02 '19 at 12:08
  • @Bathsheba no problem mate) – h4ckthepl4net Sep 02 '19 at 12:09
  • @Bathsheba I am writing this from a phone so I haven't seen that you already answered the question – h4ckthepl4net Sep 02 '19 at 12:11
  • I'm glad - you should answer answer a question if you believe you have something to say that, perhaps, hasn't already been said. I think this answer is more useful in some ways than mine. – Bathsheba Sep 02 '19 at 12:12
6

Since C++17 you can write a constexpr function to efficiently set up the array, since the element accessors are constexpr now. This method will also work for various other schemes of setting up initial values:

#include <array>

template<typename T, size_t N>
constexpr auto make_array(T value) -> std::array<T, N>
{
    std::array<T, N> a{};
    for (auto& x : a)
        x = value;
    return a;
}

int main()
{
    auto arr = make_array<int, 10>(7);
}
M.M
  • 138,810
  • 21
  • 208
  • 365
3

As said before, the fill solution doesn't work for non-default constructible types. The index_sequence solution is correct but a bit verbose.

Given a value t (of any type) and a compile constant N, the following evaluates to the desired solution in one line.

std::apply([&](auto... dummy) {return std::array{(dummy, t)...};}, std::array<int, N>{});

See full code here: https://godbolt.org/z/jcq4fqMsE

This solution can be applied to C++17 and with some modification to earlier versions.

alfC
  • 14,261
  • 4
  • 67
  • 118
2

The std::array type is an aggregate that supports list-initialization:

std::array<int, 10> a{2, 2, 2, 2, 2, 2, 2, 2, 2, 2};

It also supports aggregate-initialization:

std::array<int, 10> a = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2};

This is inconvenient and error-prone for long arrays, and you would be better off using a solution like Jarod42’s for those.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Davislor
  • 14,674
  • 2
  • 34
  • 49
  • 3
    This is inconvenient and error-prone for _any_ array length. – Jabberwocky Sep 03 '19 at 08:51
  • 3
    @Jabberwocky The accepted answer is great and I upvoted it. It’s also kind of overkill for an array of three elements. The others don’t work for a `constexpr std::array`. So this technique is sometimes appropriate. – Davislor Sep 03 '19 at 16:33
0

This can be done fairly easily by creating a function template that return the required array as shown below. It is even possible to initialize the array at compile time!(see the c++17 example demo given at the end of the answer).

template<std::size_t N> std::array<int, N> make_array(int val)
{
    std::array<int, N> tempArray{};    //create local array
    for(int &elem:tempArray)           //populate it 
    {
        elem = val;                     
    }
    return tempArray;                   //return it
}
int main()
{
    //---------------------V-------->number of elements  
    auto arr  = make_array<10>(7);
    //------------------------^---->value of element to be initialized with

    
    //lets confirm if all objects have the expected value 
    for(const auto &elem: arr)
    {
        std::cout << elem << std::endl; //prints all 7 
    }
    
}

Demo


Note also that it is even possible to do this at compile time with C++17. Demo C++17

Jason
  • 36,170
  • 5
  • 26
  • 60
0

From C++20 the ranges have fill

std::array<int, 10> a2;
std::ranges::fill(a2, 10);

Also, if the array is a small (for larger ones it may look odd), from C++17 (argument deduction)

auto a = std::array{2,2,2,2};
Pavan Chandaka
  • 11,671
  • 5
  • 26
  • 34