Initialization of compound class at creation

Hi,

I have searched the net, but did not find an answer to my question,
hope you can help me. In case I overlooked some obvious answer,
please flame away!

I have a class that requires an init value at creation time,
something like:

1
2
3
4
5
6
7
8
9
10
class Foo
{
public:
    Foo(int a)
    {
        v=a;
    }
private:
    int v;
};


There is no creator without argument, so initialization is mandatory.
I like that.

From this class, I construct a templated compound class,
something like:

1
2
3
4
5
6
7
8
9
10
11
#include <array>

template<int N> class Bar
{
public:
    Bar():???
    {
    }
private:
    array<Foo,N> w;
};


The question marks indicate my problem.
By definition of Foo, w needs to be initialized at creation time.
The standard forbids initialization in the private: section,
and only allows initialization of the w member after Bar():.
(So the compiler kindly informs me.)

Preferrably, I would like to use an argument in the Bar creator,
like Bar(int p):???, where the int p would figure in the unknown spell,
alongside w of course.

So the question is: how to initialize w?

Many thanks in advance!
Do it in the constructor.

eg:

1
2
3
4
5
class foo{
   int x;
   public:
      foo(int a):x=a{}   //this means x=a, when creating an object of type foo.
};                       //another way of doing it instead of foo{x=a;} 
Last edited on
Your first class would be normally written a little differently
1
2
3
4
5
6
7
8
9
class Foo
{
public:
    Foo(int a) : v(a) 
    {
    }
private:
    int v;
};


Which is the same for most other types:

1
2
3
4
5
6
7
8
9
10
11
#include <vector>

template<int N, class Foo> class Bar
{
public:
    Bar(Foo val): w(N, val)
    {
    }
private:
    std::vector<Foo> w;
};


array is a little special because it has no constructors other than default and copy, so you'll have to write actual code that populates it, something like

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <array>
#include <algorithm>

template<int N, class Foo> class Bar
{
public:
    Bar(Foo val)
    {
        std::fill_n(w.begin(), N, val);
    }
private:
    std::array<Foo, N> w;
};


(or perhaps something like Bar(Foo val) : w(make_array<N>(val)) {}, if you write a suitable make_array)


Last edited on
Hi Cubbi,

Many thanks for your reply!

I would like to use the array template and not the vector template,
as I presume that it will generate faster code. Performance is key.

The populating-code does not work, as the error is generated at compile-time,
not at run-time. The compiler needs to generate code to _create_ the
array of Foo-s, and it is (rightfully so) not satisfied with the code in the
body of the creator, which does not necessarily do anything
with the array of Foo-s.

Writing the make_array seems only to shift the problem, but not solve it.
In the make-array function, I would have to create the array first,
before filling it with copies of val. How do I create the array?

So, unless I am overlooking something, it seems like it is impossible
to use the array template, and that I am forced to use the vector template.
And only because the array template does not have a constructor
of the form array<Foo,N>(Foo val).
Do you have any idea why the array template does not have such a constructor?

Many thanks!
Hi Aceix,

The problem I have is in the construction of Bar.
Foo requires initialization at creation time,
either with my original code or with your alternative code.

It is the initialization-at-creation-time requirement of Foo
that generates the compiler errors for Bar when using
the array template. And I would not want to release
this initialization-at-creation-time requirement of Foo,
as it will catch many errors later on!
I presume that it will generate faster code

Why do you presume that, and what code specifically? They are both arrays, so iteration, for example, compiles to identical code. Some operations, specifically, swapping and moving, are much faster with vectors.

the error is generated at compile-time. The compiler needs to generate code to _create_ the array of Foo-s

Oh, now I understand. Your question is how to create a class template with an std::array<Foo, N> member, where Foo is not default constructible.

I presume (you didn't quite specify it) that the desired contents of the array in this case are N copies of Foo.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
#include <array>

template<int... Indices>
struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};

template<int Size>
struct build_indices {
    using type = typename build_indices<Size - 1>::type::next;
};

template<>
struct build_indices<0> {
    using type = indices<>;
};

template<int N>
typename build_indices<N>::type make_indices() { return {}; }

template<typename T, int... Indices>
auto make_array_helper(const T& val, indices<Indices...>)
     -> std::array<T, sizeof... Indices>
{
    return {{ ((void)Indices, val)... }};
}

template<int N, typename T>
std::array<T, N> make_array(const T& val)
{
    return make_array_helper(val, make_indices<N>());
}

struct Foo {
   int val;
   Foo(int n) : val(n) {}
};

template<int N>
struct Container {
    std::array<Foo, N> a;
    Container(int n) : a(make_array<N>(Foo(n))) {}
};

int main()
{
    Container<10> c(7);
    for(Foo& f : c.a)
        std::cout << f.val << ' ';
    std::cout << '\n';
}
online demo: http://liveworkspace.org/code/8997fea567e9a10df1360b676f738d3c

this can be made simpler, I don't have much time, so I just reused somebody's tuple-indexing code.
(here's a link for somewhat more organized tuple indexing for the curious http://gitorious.org/redistd/redistd/blobs/master/include/redi/index_tuple.h )
Last edited on
Hi Cubbi,

Why do you presume that, and what code specifically? They are both arrays, so iteration, for example, compiles to identical code. Some operations, specifically, swapping and moving, are much faster with vectors.

Vectors can change size dynamically, so I had presumed that this flexibility would lead or overhead here or there (I'm not familiar enough with the implementation of vectors to know where.) But if in general the vector-based code is equal or even better with vectos, I'll happliy use them!

Of course, this does beg the question of why arrays exist at all. Can you indicate a situation where it is better to use arrays rather than vectors?

Oh, now I understand. Your question is how to create a class template with an std::array<Foo, N> member, where Foo is not default constructible.

Yes, that is indeed the question. Apologies if that was not immediately clear. I had spent some time bringing down the problem to its essence, and the example with the two classes was the simplest I could find.

I presume (you didn't quite specify it) that the desired contents of the array in this case are N copies of Foo.

Indeed I did not specify exactly how to initialize the Foo array, in order not to exclude some simple solution. The main problem is the creation of Bar, not the specific initialization of all the Foo-s.

Initializing them to a value specified in the Bar class would be the lowest option. If no other solutions would exist, that would already be acceptable. A more attractive solution is to have the initialization value specified by the entitiy that creates the Bar. A single value that is copied into all array elements is then the base case. Allowing the creator to specify all values would again be a step up.

===========

Thank you for providing the code! I certainly need to study this, as I am unfamiliar with the ...-constructs. I also spotted some compile-time recursion in the build_indices struct. Nifty!

All in all, I think I will set up my code using vectors, this should lead to an acceptable solution. For my education, do you know why the array template does not have a constructor of the form array<T,N>(value)?

Can you indicate a situation where it is better to use arrays rather than vectors?


construction, copying, and destruction is cheaper for arrays (no allocator call), so it you're generating millions of short arrays a second, cloning them, and destroying them, using vectors would be a bad idea. (But, as mentioned, vectors win at moving and swapping, so std::sort()'ing a vector of arrays is slower than sorting a vector of same-length vectors)

Also, heap memory use is sometimes prohibited or unwelcome, and stack allocators may be unavailable or unnecessarily complex

why the array template does not have a constructor of the form array<T,N>(value)

Back when it was created (1999), its goal was to make arrays usable with then new C++ library facilities (iterators and algorithms), while still making it possible to initialize them as aggregates (T a = {1,2,3}). If a struct has a constructor, it can't use aggregate initialization.
Topic archived. No new replies allowed.