Although you can't initialise an array in-place like that, you can do almost the same thing by creating a recursive struct
:
template <int I>
struct squared {
squared<I - 1> rest;
int x;
squared() : x((I - 1) * (I - 1)) {}
};
template <>
struct squared<1> {
int x;
squared() : x(0) {}
};
Then later in your code you can declare:
squared<5> s;
and the compiler will indeed create a struct
containing 5 int
s: 0, 1, 4, 16, 25.
A couple of notes:
- My interpretation of the C++ standard is that it stops short of guaranteeing that this
struct
will be laid out identically to an array. While it is a POD type, and POD types are guaranteed to be laid out "contiguously" in memory (1.8/5) with the first member at offset 0 (9.2/17) and later members at higher addresses (9.2/12), and arrays are also laid out "contiguously" (8.3.4/1), the standard doesn't say that arrays are layout-compatible with such struct
s. However, any sane compiler will lay these objects out identically.
- C++ requires that even an empty
struct
be at least 1 byte long. If it did not, we could go with a slightly cleaner formulation in which the base case of the recursion was I == 0
and we didn't subtract 1 from I
for the calculations.
It would be nice if we could place this struct
inside a union
with an array of the appropriate size, to make it easy to access the members. Unfortunately, C++ bans you from including an object in a union
if that object has a non-trivial constructor. So the easiest way to get at the i
th element is with a good old-fashioned cast:
squared<5> s;
cout << "3 squared is " << reinterpret_cast<int*>(&s)[3] << endl;
If you wanted, you could write an overloaded operator[]()
function template to make this prettier.