4

I want to create a constant and static integer array as a public class variable. It is neat to define it and initialize it right away. See code below for complete example.

#include <iostream>

class Foo {
public:
    constexpr static int arr[3][2] = {
            {1, 2},
            {3, 4},
            {5, 6}
    };
};

int main() {
    for (int i = 0; i < 3; i++) {
        std::cout << "Pair " << Foo::arr[i][0] << ", " << Foo::arr[i][1] << std::endl;
    }
    return 0;
}

However, compiling code above using g++ --std=c++11 test.cpp produces

/usr/bin/ld: /tmp/ccc7DFI5.o: in function `main':
test.cpp:(.text+0x2f): undefined reference to `Foo::arr'
/usr/bin/ld: test.cpp:(.text+0x55): undefined reference to `Foo::arr'
collect2: error: ld returned 1 exit status

Is this not possible in C++ ? More likely I am missing some part about C++ and its static variable initialization policy.

Talos
  • 457
  • 4
  • 15
  • clang runs it gcc doesn't live https://godbolt.org/z/xavEde have an up vote and concider adding [language-lawyer] Follow up gcc runs it with `-std=c++17` – Richard Critten Feb 28 '21 at 19:39
  • 1
    GCC accepts it with -std=c++17. IIRC, such inline definitions of static class data members came with C++14 or C++17. Other compilers may have incorporated it earlier, as an extension. See [here](https://stackoverflow.com/q/38043442/10871073) – Adrian Mole Feb 28 '21 at 19:46

2 Answers2

6

Before C++17 (so C++11 and C++14) you have to add

constexpr int Foo::arr[3][2];

outside the body of class.

max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    This is also a solution. However, not a very neat one. – Talos Feb 28 '21 at 20:08
  • 1
    @Talos This was the standard method for static member variables until C++17 . Have you got something better in mind, for C++11 ? – M.M Feb 28 '21 at 20:17
  • @M.M initializing constant static array inside body of the class in one line – Talos Feb 28 '21 at 20:21
  • 2
    @Talos You also need the out-of-class definition, prior to C++17 – M.M Feb 28 '21 at 20:21
  • @Talos, in class definition would solely work for integral values in C++11. Gcc is right here in rejecting the code for C++11. Didn't check that with a "real" Clang at home but I'd guess on GodBolt, some linkage simplifications might be persistent, forcing the array to have internal linkage there. – Secundi Feb 28 '21 at 20:42
1

Compiler error was due to the C++11 standard.

Using C++17 standard by compiling above code using

g++ --std=c++17 test.cpp

produces no errors.

EDIT: This solution applies to C++17 and not C++11 as in my original question. For C++11 solution see accepted answer.

Talos
  • 457
  • 4
  • 15
  • 1
    Although, despite my comment(s) on your question, it seems that the C++11 standard does support this. This [cppreference page](https://en.cppreference.com/w/cpp/language/static) suggests that `constexpr static int arr[] = { 1, 2, 3 };` (in a `struct`) is "OK" since C++11. – Adrian Mole Feb 28 '21 at 20:01
  • 4
    @AdrianMole It is OK since C++11, but also requires an out-of-class definition as per max66's answer. Prior to C++11 `constexpr` was not a keyword – M.M Feb 28 '21 at 20:18
  • The question is tagged C++11 so this solution is not applicable – M.M Feb 28 '21 at 20:19
  • 1
    @AdrianMole True... but perhaps this would be an appropriate spot for OP to edit the question to clarify that they are open to using later versions of the language – M.M Feb 28 '21 at 20:21