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
CodePudding user response:
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{};
CodePudding user response:
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; }
};
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{};