2

I found various answers to questions about how to instantiate static members of C++ template classes with type parameters (for example https://stackoverflow.com/a/3229904/2995726), but I'm unable to apply this to a template class with integer parameter(s).

I tried this, with the additional complication that the template parameter has a default value:

$ cat test.cc
#include <iostream>

template<unsigned int a = 33>
class A
{
public:
    static unsigned char x;

    static unsigned int f(void) { return x + a; }
};

// Instantiate template
template class A<>;

// Attempts to instantiate static member:
// unsigned char A<>::x;
// template<> unsigned char A<>::x;
// template<unsigned int> unsigned char A<>::x;

int main(void)
{
    A<>::x = 3;

    std::cout << A<>::f() << std::endl;
}

When I try to compile this with g++ 10.2, I get a linker error:

$ g++ -std=c++14 -o foo test.cc
/usr/bin/ld: /tmp/ccXGU1fT.o: in function `main':
test.cc:(.text+0x7): undefined reference to `A<33u>::x'
/usr/bin/ld: /tmp/ccXGU1fT.o: in function `A<33u>::f()':
test.cc:(.text._ZN1AILj33EE1fEv[_ZN1AILj33EE1fEv]+0x7): undefined reference to `A<33u>::x'
collect2: error: ld returned 1 exit status

The three commented lines are attempts to instantiate the static member variable. When I enable the following line:

unsigned char A<>::x;

then this happens:

test.cc:16:15: error: specializing member ‘A<>::x’ requires ‘template<>’ syntax
   16 | unsigned char A<>::x;
      |               ^~~~

Using this line:

template<> unsigned char A<>::x;

again results in a linker error:

$ g++ -std=c++14 -o foo test.cc
/usr/bin/ld: /tmp/ccmw49ld.o: in function `main':
test.cc:(.text+0x7): undefined reference to `A<33u>::x'
/usr/bin/ld: /tmp/ccmw49ld.o: in function `A<33u>::f()':
test.cc:(.text._ZN1AILj33EE1fEv[_ZN1AILj33EE1fEv]+0x7): undefined reference to `A<33u>::x'
collect2: error: ld returned 1 exit status

And finally the line:

template<unsigned int> unsigned char A<>::x;

results in this error:

$ g++ -std=c++14 -o foo test.cc
test.cc:18:43: error: template parameters not deducible in partial specialization:
   18 | template<unsigned int> unsigned char A<>::x;
      |                                           ^
test.cc:18:43: note:         ‘<anonymous>’
test.cc:25: confused by earlier errors, bailing out
stm
  • 662
  • 1
  • 6
  • 23

2 Answers2

3

Instead of "Instantiate template" you need to define the static variable which currently is only declared.

A definition could look like this:

template<unsigned int a>
unsigned char A<a>::x{};

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thanks, when removing the "Instantiate template" line and with your suggested definitin of "x" it compiles and the program prints the expected result "36". Do I understand it correctly that this definition implicitly defines the static member variable for all other instantiations of the class as well? I was able to add the following line to the main program: std::cout << A<42>::f() << std::endl; The program compiles and then prints: 36 42 So the static member "x" was also defined for class "A<42>" apparently. – stm Apr 24 '22 at 12:36
  • 1
    @stm It will be instantiated for every instance of the template you have, so yes. If you have 2 instances of the template, you will get two instances of x. – Ted Lyngmo Apr 24 '22 at 12:40
3

The problem is that currently we only have a declaration for the static data member x inside the class template. So to solve this, we need to provide a definition for the static data member x. With C++17 you can use inline to define the static data member x inside the class template so that an out-of-class definition of the static data member is not needed anymore, as shown below:

template<unsigned int a = 33>
class A
{
public:
    inline static unsigned char x{}; //inline used here

    static unsigned int f(void) { return x + a; }
};

Demo

Pre-C++17

For Pre-C++17 standard, we have to provide an out-of-class definition for the static data member:

//out-of-class definition for Pre-C++17
template<unsigned int a>
unsigned char A<a>::x{};

Jason
  • 36,170
  • 5
  • 26
  • 60