2

Essentially I want a template class with an array whose size is a template parameter, to hold constant content.

Something like:

template<size_t S> struct Foo {
    const int bar[S];
    Foo(const int(&par)[S]) : bar(par) {
        cout << "bar size is " << S << endl;
    }
};
auto foo = Foo({1,2,3});

I have been searching and tinkering a bit, and almost have a workaround implemented with an intermediate static method and using std::array:

template<size_t S> struct Baz {
  const array<int,S> qux;
  Baz(const array<int,S>&par) : qux(par) {
    cout << "size is " << S << endl;
  }
};
template<size_t S> Baz<S>
GetBaz(const array<int,S>&in) {
  return Baz<S>(in);
}

int main() {
  auto sample = GetBaz({1,2,3});
  return 0;
}

... Which is already quite some boilerplate, but still the std::array does not seem to get constructed from an initialiser list? :-(

prog.cpp: In function 'int main()':
prog.cpp:27:30: error: no matching function for call to 'GetBaz(<brace-enclosed initializer list>)'
  auto sample = GetBaz({1,2,3});
gatopeich
  • 3,287
  • 31
  • 26
  • You cannot do this with built-in array, must use `std::array` – M.M Mar 26 '16 at 10:10
  • For `auto sample = GetBaz({1,2,3});` it fails because you need to specify `GetBaz<5>` or whatever. Initializer list length is not part of their type. – M.M Mar 26 '16 at 10:11
  • 1
    [The code in this answer](http://stackoverflow.com/a/6114359/1505939) may help you solve your problem, if you're willing to use `GetBaz(1,2,3)` without the extra braces – M.M Mar 26 '16 at 10:33

3 Answers3

5

Post-DR1591 built-in array bound are now deducible from a braced-init-list, so:

template<size_t S> struct Baz {
  const array<int,S> qux;
  Baz(const array<int,S>&par) : qux(par) {
    cout << "size is " << S << endl;
  }
  Baz(const int (&par)[S]) : qux(std::experimental::to_array(par)) {}
};

template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
  return Baz<S>(in);
}

std::experimental::to_array creates an std::array from a built-in one. See the linked cppreference page for implementation.

You can go built-in arrays all the way, but it's somewhat more annoying:

template<size_t S> struct Baz {
  const int bar[S]; 

  template<size_t... Is>
  Baz(const int (&par)[S], std::index_sequence<Is...>)
      : bar { par[Is]... } {}

  Baz(const int (&par)[S]) : Baz(par, std::make_index_sequence<S>()) {}
};

template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
  return Baz<S>(in);
}
T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Thanks, I am not a fan of using `experimental` but your answer is very clarifying and answers the question. – gatopeich Mar 26 '16 at 17:05
  • BTW, do you know an equivalent with old style arrays? I still don't understand why std::array was added instead of improving what was already there. – gatopeich Mar 26 '16 at 17:07
2

Not sure if I fully understood the questions. Is that what you are trying to achieve?

#include <iostream>
#include <array>

template<size_t S> struct Baz {
    const std::array<int,S> qux;
    Baz(const std::array<int,S>& par) : qux(par) {
        std::cout << "size is " << qux.size() << std::endl;
    }
};

int main() {
    auto sample = Baz<5>({1,2,3}); // size = 5, values = 1, 2, 3, 0, 0
    return 0;
}

Summary:

  1. Use an std::array instead of a raw array.
  2. Specify the template argument, eg: Baz<5>(...). Class template arguments are not deduced.
sergej
  • 17,147
  • 6
  • 52
  • 89
  • Precisely, I want the array size to be inferred :-). I know class template arguments cannot be deduced _from constructor_, but I am ready to use a static function `GetBaz()` for that. The issue I cannot solve in an good looking way is passing the initializer list through the intermediate function into the constructor. – gatopeich Mar 26 '16 at 12:40
0

You can do it with a classic C array, but using a variadic constructor

#include <array>
#include <cstddef>
#include <iostream>

using namespace std;

template <size_t S> struct Foo {
    const int bar[S];
    const std::array<int, S> bar2;

    template <typename ... I>
       Foo (const I & ... i) : bar {i...}, bar2 {{i...}}
    {
      cout << "bar size is " << S << " == " <<
         (sizeof(bar)/sizeof(bar[0])) << " == " << bar2.size() << endl;
    }
};

int main()
 {
   Foo<3>  foo {1,2,3};

   auto  foo2 = Foo<4>{1,2,3,4};

   return 0;
 }
max66
  • 65,235
  • 10
  • 71
  • 111