Re: Question on CRTP static member initialization with GCC
On Mon, 21 Jul 2014 18:32:46 -0700 (PDT)
arkadiy@cardspring.com wrote:
I'm trying to use CRTP for static inheritance, like so:
parent.h:
template<typename Derived>
class Parent {
static int s_number;
};
child.h:
class Child : Parent<Child> {
};
When I try to use Child::s_number I get a "Symbol not found" runtime
error. It seems that since template instantiation is lazy I need to
force it to initialize with:
(solution 1)
child.cpp:
template<>
int Child::Parent<Child>::s_number = 0;
However I have many child classes and it is a pain to initialize that
everywhere, so I tried the solution in this post:
http://stackoverflow.com/questions/24725152/force-explicit-template-instantiation-with-crtp
Namely by doing:
(solution 2)
template <typename T, T>
struct NonTypeParameter {};
typedef NonTypeParameter<int&, s_number> dummy;
After additional testing I've found that if I use only solution 1
then I won't get any crashes when compiling with GCC 4.7.3 on my
Linux Ubuntu machine, but it does crash using GCC 4.7.3 on my Mac.
Using only solution 2 it will work on my Mac, but crash on my Linux
machine. Using both solutions it compiles successfully and doesn't
crash anywhere.
Has anyone encountered this problem before, and/or knows a portable
way of making sure CRTP static members are initialized properly?
If you make 's_number' a public member and use public instead of private
inheritance so that it is accessible, and declare the member in the
header, it should work (see below). This will share the s_number
variable amongst all Parent classes having the same Derived type. If
you want to have a variable which is shared amongst all Parent objects
irrespective of the Derived type, you will need to have a global
variable. If you have an order-of-instantiation/initialisation hiatus
in your code, you may want to instantiate 's_number' explicitly at a
time of your choosing rather than let the compiler do it when ODR-used,
say by an explicit 'template <> int Parent<Child>::s_number = 0'
statement in a suitable *.cpp (non-header) file, but normally that is
not necessary.
By the way, when your refer to a "runtime" error presumably you really
mean a link-time error?
Chris
parent.h:
template<typename Derived>
class Parent {
public:
static int s_number;
};
template<typename Derived>
int Parent<Derived>::s_number = 0;
child.h:
class Child : public Parent<Child> {
};