46

I have just found out that the following is not valid.

//Header File
class test
{
    const static char array[] = { '1', '2', '3' };
};

Where is the best place to initialize this?

Donald Duck
  • 7,638
  • 19
  • 69
  • 90
user174084
  • 1,047
  • 3
  • 14
  • 23

6 Answers6

53

The best place would be in a source file

// Header file
class test
{
    const static char array[];
};

// Source file
const char test::array[] = {'1','2','3'};

You can initialize integer types in the class declaration like you tried to do; all other types have to be initialized outside the class declaration, and only once.

midor
  • 5,223
  • 1
  • 20
  • 51
Mike Seymour
  • 242,813
  • 27
  • 432
  • 630
  • Shouldn't that say "... in the class *declaration*..."? I thought `.h` were declarations and `.c` were definitions, hence why taking a reference to an integer type that is declared only in the header results in a compiler error: `undefined reference to test::SOME_INTEGER`? (I realize this sounds super nit-picky and pedantic, and I'm not trying to be difficult; I just want to make sure I'm using the right terminology, so definitely correct me if I'm wrong). – dwanderson Feb 15 '16 at 15:55
36

You can always do the following:

class test {
  static const char array(int index) {
    static const char a[] = {'1','2','3'};
    return a[index];
  } 
};

A couple nice things about this paradigm:

JKD
  • 603
  • 5
  • 8
21
//Header File 
class test 
{ 
    const static char array[];
}; 

// .cpp
const char test::array[] = { '1', '2', '3' }; 
peterchen
  • 39,809
  • 19
  • 101
  • 181
12

Now, in C++17, you can use inline variable

How do inline variables work?

A simple static data member(N4424):

struct WithStaticDataMember {
  // This is a definition, no out­of­line definition is required.
  static inline constexpr const char *kFoo = "foo bar";
};

In your example:

//Header File
class test
{
    inline constexpr static char array[] = { '1', '2', '3' };
};

should just work

Community
  • 1
  • 1
lz96
  • 2,599
  • 2
  • 26
  • 44
2

With constexpr you must define the value on the header even in C++11

If you use constexpr instead of const, then this answer suggests that you not only can, but must, define on header even in 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://stackoverflow.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);
}

Compile and run with:

g++-10 -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out 

If instead you try:

struct MyClass {
    static constexpr int is[];
};

constexpr int MyClass::is[] = {1, 2, 3};

compilation fails with:

main.cpp:4:26: error: ‘constexpr’ static data member ‘is’ must have an initializer

Tested on Ubuntu 20.04.

0

This is kind of an abuse of the system, but if you REALLY want to define it in the header file (and you don't have C++17), you can do this. It won't be a static member, but it will be a constant that only takes up storage per compilation unit (rather than per class instance):

(Put all of this code in the header file.)

namespace {
    const char test_init_array[] = {'1', '2', '3'};
}

class test {
public:
    const char * const array;

    test() : array(test_init_array) {}
};
Jim Hunziker
  • 12,836
  • 7
  • 54
  • 59