Jabberwocky
Jabberwocky

Reputation: 50775

Initializing a std::array with all elements having the same value

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.

Upvotes: 56

Views: 33926

Answers (8)

alfC
alfC

Reputation: 16242

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.

Upvotes: 5

Pavan Chandaka
Pavan Chandaka

Reputation: 12751

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

Upvotes: 1

user12002570
user12002570

Reputation: 1

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

Upvotes: 0

Jarod42
Jarod42

Reputation: 217275

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.

Upvotes: 45

M.M
M.M

Reputation: 141576

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

Upvotes: 6

Davislor
Davislor

Reputation: 15144

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.

Upvotes: 2

h4ckthepl4net
h4ckthepl4net

Reputation: 681

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>

Upvotes: 31

Bathsheba
Bathsheba

Reputation: 234715

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

Upvotes: 38

Related Questions