const char* ch = "hello";
is sort of like
static const char string_literal[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
const char* ch = &string_literal[0];
except that each identical string literal does not necessarily point to a distinct location in memory.
The same is also possible for any other type:
static int integer_list[] = { 1, 2, 3 };
int* i = &integer_list[0];
// or equivalently, just int* i = integer_list;
Now, i[0]
is 1
, i[1]
is 2
, and i[2]
is 3
.
There is a special syntax for string literals, because they are so frequently used, and so frequently in contexts where it is not desirable to clutter the code with dummy variables.
If you've got a lot of code that uses statically allocated read-only arrays of integer type, you may be able to hide the boilerplate using templates:
template <int a, int b, int c>
struct int_array { static const int values[3]; };
template <int a, int b, int c>
const int int_array<a, b, c>::values[] = { a, b, c };
You only need to define the template once, and then each different user can use that template for the specific values that user is interested in.
const int* i = int_array<1, 5, 6>::values;
Often, it will be easier to simply define a separate array variable, but there are cases where such a template helps.
As noted in the comments, it's possible to define the template more generically, so that it works for arrays of arbitrary type and arbitrary length, but it requires an up-to-date compiler with good support for the current version of C++ (for GCC and clang, current versions are fine, but make sure to pass the -std=c++11
or -std=gnu++11
option to enable C++11 features):
template <typename T, T... v>
struct static_array {
static const T values[sizeof...(v)];
};
template <typename T, T... v>
const T static_array<T, v...>::values[sizeof...(v)] = { v... };
Now, the syntax for a user of this array is
const int* i = static_array<int, 1, 2, 3, 4>::values;
const unsigned* j = static_array<unsigned, 1, 2, 3, 4, 5>::values;