Reputation: 50775
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
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
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
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
}
}
Note also that it is even possible to do this at compile time with C++17. Demo C++17
Upvotes: 0
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
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
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
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
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