3

I have a simple example where I create an std::array of some number of Foo elements:

struct Foo
{
     Foo(int bar=0) : m_bar(bar) 
     {
       // Code depending on the value of bar
     }

     int m_bar;
};

const unsigned int num = // get array size 
std::array<Foo, num> fooArr;

When I use the initialiser list in the constructor m_bar(bar) this sets all the Foo.m_bar to 0 (as this is the default constructor parameter value). If I don't do that then it is full with garbage values.

My question is how do I pass in another value different from the default one to the constructor of every element in the array without knowing the array size before hand?

I tried using a init list when creating the array, like so: std::array<Foo, 5> fooArr{3} but that only sets the first element's m_bar to 3.

9
  • 1
    What about fooArr{{1,2,3,4,5}}? Commented Sep 17, 2015 at 9:35
  • Sorry it wasn't very clear but I shouldn't know the array size before hand, to be able to do that. I've edited the question accordingly. Commented Sep 17, 2015 at 9:39
  • In Cppreference there is this example: std::array<std::string, 2> a3 = { std::string("a"), "b" }; Is it what you are searching for? Commented Sep 17, 2015 at 9:41
  • Do you know the size in compile time or is it defined by a preprocessor define? Commented Sep 17, 2015 at 9:43
  • 3
    std::array<Foo, 5> and "without knowing the array size" make things unclear. Commented Sep 17, 2015 at 9:48

2 Answers 2

6

You should simply default-construct the std::array then use its fill method to populate it with a fixed value. Many compilers can optimize this effectively, so you won't pay for the "extra" initialization.

To satisfy your use case, the code would look something like this:

fooArr.fill(Foo(3));
Sign up to request clarification or add additional context in comments.

8 Comments

The problem with that (unless i misunderstand what you mean) is that if I have code in the constructor of Foo() which depends on the value of size it will still get 0's wont it?
I would even wrap it up in a convenience function to use it in initialization.
@G.Rassovsky What is size and how does Foo know anything about it?
arrrgh, my bad i meant to say bar not size, sorry.
You'd do fooArr.fill(Foo(3)) to satisfy your example. bar would be 3 in the anonymous temporary Foo, which would then be copied to all the array elements.
|
4

Make an integer_sequence with N elements, and build the array with a pack expansion. This is more useful if your default constructor does nontrivial work or doesn't exist.

template<std::size_t N, class T, std::size_t... Ns>
std::array<T, N> make_repeating_array(const T& value, std::index_sequence<Ns...>) {
    return {(void(Ns), value)... };
}

template<std::size_t N, class T>
std::array<T, N> make_repeating_array(const T& value) {
    return make_repeating_array<N>(value, std::make_index_sequence<N>());
}

Use as

std::array<Foo, num> fooArr = make_repeating_array<num>(Foo(5));

4 Comments

I appreciate the example even though i'm not exactly sure how it works. I've accepted John Zwinck's answer as it is simpler and works for my case but please keep yours up as I can imagine this being more useful in more complex situations.
What is the (void(Ns), value) for?
@xtofl Essentially, it repeats value sizeof...(Ns) (which is N) times. The , is the comma operator.
Can the array size be determined from sizeof...(Ns) in make_repeating_array ?

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.