0

It is not a very neat idea. but, I intend to write a class with a static member being a derived instance of itself. (actually, my class is a kind of abstract container and I am sharing a concrete instance of a simple empty container for performance reasons).

I checked this code and it compiles OK :

class B;

class A {
public :
  static B b;
};

class B : public A
{};

int main()
{
 A a;
}  

But my class is actually a template one :

template<typename T>
class B;

template<typename T>
class A {
public :
  static B<T> b;
};

template<typename T>
class B : public A<T>
{};

int main()
{
 A<int> a;
}

Unfortnuately, I now have a compiler error :

main_ko2.cpp: In instantiation of ‘class B<int>’:
main_ko2.cpp:7:15:   required from ‘class A<int>’
main_ko2.cpp:14:9:   required from here
main_ko2.cpp:10:7: error: invalid use of incomplete type ‘class A<int>’
   10 | class B : public A<T>
      |       ^
main_ko2.cpp:5:7: note: declaration of ‘class A<int>’
    5 | class A {
      |       ^

Note that if I add the following line in my main() function

int main()
{
 B<int> b; //!< added
 A<int> a;
}

Now, the code compiles OK !

As it is an uncommon (probably for good reason) programming pattern, maybe I stand in the dark areas where compiler behavior is unspecified. Maybe other compilers would behave differently than mine : g++ (Ubuntu 11.3.0-1ubuntu1~22.04 11.3.0)

What do you think ? Would there be a trick to make the compilation works ?

I don't think creating global variables would be a good solution as I want an instance for any types in my template argument.

  • I'd guess it's this problem: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?r=Saves_AllUserSaves – πάντα ῥεῖ May 11 '23 at 10:54
  • You can force instantiation of a template without adding a variable. See here: https://stackoverflow.com/questions/2152002/how-do-i-force-a-particular-instance-of-a-c-template-to-instantiate. Basically you need to add e.g. `template class B;` before `main`. – wohlstad May 11 '23 at 11:19
  • Maybe CRTP can help ? I don't know the specific visibility you're aiming for for each class, but maybe an implementation base class `A_detail` could use CRTP to have `class B : public A_detail>` Also, maybe the pImpl idiom can help in hiding the implementation detail ? – Nebular Noise May 11 '23 at 12:52

1 Answers1

2

You can avoid both your error and the Static Initialization Order Fiasco by using a function static which creates your instance when it's first called. You can then define this method once B is fully defined:

template<typename T>
class A {
public :
  static A& instance();
};

template<typename T>
class B : public A<T>
{};

template<typename T>
A<T>& A<T>::instance()
{
    static B<T> b;
    return b;
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60