59

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.

2

8 Answers 8

48

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.

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

11 Comments

This is the most elegant solution for my needs. Very similar to the non compiling std::array<int, 10> a(7) which becomes auto a = create_array<10, int>(7) or even auto a = create_array<10>(7)
What's the difference of all this to just a method with a foreach inside?
@mFeinstein: "contrary to std::fill solution, handle non default constructible type.".
So std::fill is a foreach?
@einpoklum: in that context, it is T which might be evil.
|
39

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

Comments

31

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>

4 Comments

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 no problem mate)
@Bathsheba I am writing this from a phone so I haven't seen that you already answered the question
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.
11

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 modifications to earlier C++ versions.


EDIT:

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

1 Comment

This is an excellent solution. I will note that adding a (void) cast before dummy in the array arguments (making ((void)dummy, t) can get rid of unused-value warnings from g++ and clang++ and at least in my testing still produces the desired result
7

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);
}

5 Comments

Requires default constructible T though.
Also, no need to value initialize the std::array before initializing with value.
@ggg no harm in following good general habits
@M.M You don't pay for what you don't use.
@ggg you do pay for errors due to uninitialized variables in other situations
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.

2 Comments

This is inconvenient and error-prone for any array length.
@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.
2

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};

Comments

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

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.