Инициализация статического массива констант в заголовочном файле
Я только что узнал, что следующее недействительно.
//Header File
class test
{
const static char array[] = { '1', '2', '3' };
};
Где лучшее место для инициализации этого?
4 ответа
Лучшее место было бы в исходном файле
// Header file
class test
{
const static char array[];
};
// Source file
const char test::array[] = {'1','2','3'};
Вы можете инициализировать целочисленные типы в объявлении класса, как вы пытались это сделать; все остальные типы должны быть инициализированы вне объявления класса и только один раз.
Вы всегда можете сделать следующее:
class test {
static const char array(int index) {
static const char a[] = {'1','2','3'};
return a[index];
}
};
Пара хороших вещей об этой парадигме:
- Нет необходимости в файле cpp
- Вы можете сделать проверку диапазона, если вы хотите
- Вам не нужно беспокоиться о фиаско статической инициализации
//Header File
class test
{
const static char array[];
};
// .cpp
const char test::array[] = { '1', '2', '3' };
Теперь в C++17 вы можете использовать встроенную переменную
Как работают встроенные переменные?
Простой элемент статических данных ( N4424):
struct WithStaticDataMember { // This is a definition, no outofline definition is required. static inline constexpr const char *kFoo = "foo bar"; };
В вашем примере:
//Header File
class test
{
inline constexpr static char array[] = { '1', '2', '3' };
};
должен просто работать
С constexpr
вы должны определить значение в заголовке даже в C++11
Если вы используете constexpr
вместо того const
, то этот ответ предполагает, что вы не только можете, но и должны определять заголовок даже в C++11:
#include <cassert>
struct MyClass {
static constexpr int is[] = {1, 2, 3};
static constexpr int i = 1;
};
// TODO is this ever mandatory? Create example that fails on -std=c++11.
// Pretty sure never mandatory in C++17 https://stackru.com/a/40959093/895245
// constexpr int MyClass::is[];
int main (void) {
assert(MyClass::is[0] == 1);
assert(&MyClass::is[0] == &MyClass::is[1] - 1);
assert(MyClass::i == 1);
assert(&MyClass::i == &MyClass::i);
}
Скомпилируйте и запустите с:
g++-10 -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Если вместо этого вы попробуете:
struct MyClass {
static constexpr int is[];
};
constexpr int MyClass::is[] = {1, 2, 3};
компиляция не выполняется:
main.cpp:4:26: error: ‘constexpr’ static data member ‘is’ must have an initializer
Проверено на Ubuntu 20.04.
Это своего рода злоупотребление системой, но если вы ДЕЙСТВИТЕЛЬНО хотите определить это в файле заголовка (а у вас нет C++17), вы можете это сделать. Это не будет статический член, но это будет константа, которая занимает хранилище только для каждой единицы компиляции (а не для каждого экземпляра класса):
(Поместите весь этот код в файл заголовка.)
namespace {
const char test_init_array[] = {'1', '2', '3'};
}
class test {
public:
const char * const array;
test() : array(test_init_array) {}
};