5

I want to initialize a template sized array of objects with no default constructors, as shown in following code :

#include <array>

template<std::size_t N>
class Foo
{
    public:
        class Bar
        {
                Foo<N> & _super;

            public:
                Bar(Foo<N> *super) :
                    _super(*super)
                {
                }
        };

        std::array<Bar, N>  _array;

        Foo(void) :
            _array{{}} // We need {this, ...} N times
        {
        }
};


int main(void)
{
    Foo<3>  foo;
    (void)foo;
    return 0;
}

Is it a way to say : "I want an array of N objects, all initialized with this same parameter" ? I think there is a way with the template meta programming, but I cannot figure how to do it.

Boiethios
  • 38,438
  • 19
  • 134
  • 183
  • Shouldn't `Bar`'s constructor be `Bar(Foo &super) : _super(super)`? Or member `Foo & _super` should be `Foo * _super`? – wally Apr 25 '16 at 13:53
  • @flatmouse Does not change anything, no ? I could write it and construct Bar as follow `Bar(*this)` ; but that does not help solving the question. – Boiethios Apr 25 '16 at 13:56
  • Ah ok, you are taking a pointer which is then deferenced to initialize the reference member. I was trying to understand. I get it now. – wally Apr 25 '16 at 13:58
  • related: http://stackoverflow.com/questions/17923683/why-does-stdarray-not-have-an-constructor-that-takes-a-value-for-the-array-to – NathanOliver Apr 25 '16 at 13:59
  • @NathanOliver I cannot see how it is a duplicate... – Boiethios Apr 25 '16 at 14:00
  • @Boiethios Part of my boilerplate. I forgot to remove it. – NathanOliver Apr 25 '16 at 14:03

2 Answers2

9

Everything is possible with the little help from make_index_sequence:

   Foo() : Foo(std::make_index_sequence<N>()) {} 
   template <size_t... I> Foo(std::index_sequence<I...> ) : _array{((void)I, this)...} {}

Notice the comma operator (,) in the _array constructor - courtesy of @Quentin (as opposed to function call).

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 4
    You can replace the function invocation with a comma operator : `_array{(I, this)...}` :) – Quentin Apr 25 '16 at 14:12
  • Sure ! I didn't want to post an answer that be identical to yours, save for this tweak. – Quentin Apr 25 '16 at 14:15
  • That seems a really convenient way to do this, but that necessitates the C++14. Is it possible in C++11 ? – Boiethios Apr 25 '16 at 14:16
  • @Boiethios, you can easily implement make_index_sequence in C++11. Let me post the code. – SergeyA Apr 25 '16 at 14:19
  • @SergeyA Thanks. It's because the compiler we use is C++11. – Boiethios Apr 25 '16 at 14:24
  • `((void)I, this)` removes the warning – Boiethios Apr 25 '16 at 14:30
  • @SergeyA I'd like to read your `make_index_sequence implementation` as explanation of it, but I think the @Barry version will be shortest. So I will ask for a make_index_sequence explanation in another question, and you will post this answer as its answer. – Boiethios Apr 25 '16 at 15:42
  • @Boiethios If you google C++11 make_index_sequence, [this](http://stackoverflow.com/a/17426611/2069064) is the 2nd result. – Barry Apr 25 '16 at 15:44
2

You could just keep adding one this at a time until you have N of them, at which point you just initialize _array:

    Foo()
    : Foo(this)
    { }

private:
    template <class... T, std::enable_if_t<(sizeof...(T) < N), void*> = nullptr>
    Foo(T... args)
    : Foo(args..., this)
    { }

    template <class... T, std::enable_if_t<(sizeof...(T) == N), void*> = nullptr>
    Foo(T... args)
    : _array{{args...}}
    { }  
Barry
  • 286,269
  • 29
  • 621
  • 977
  • @Boiethios The `index_sequence` approach is better. – Barry Apr 25 '16 at 14:14
  • Is it possible to write this code in C++11 (`enable_if_t` is C++14) ? For example with a template parameter `size_t I` that will decrease and a specialized version `<0>` ? I try to do this, but I have trouble with the writing of templates. – Boiethios Apr 25 '16 at 15:22
  • @Boiethios `enable_if_t` is just an alias template, you could just copy the definition in C++11. – Barry Apr 25 '16 at 15:23