Инициализация статического массива констант в заголовочном файле

Я только что узнал, что следующее недействительно.

//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];
  } 
};

Пара хороших вещей об этой парадигме:

//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 out­of­line 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) {}
};
Другие вопросы по тегам