Skip to main content
edited title
Link
DailyLearner
  • 2.3k
  • 2
  • 18
  • 26

CRTP Member VisbilityVisibility

Source Link
nick2225
  • 555
  • 1
  • 6
  • 21

CRTP Member Visbility

I am trying to better understand C++ class member visibility as it pertains to the CRTP (curiously recurring template pattern). I should note that I understand the use of CRTP and its "compile time polymorphism".

I have the following snippet of code.

// A C++ constraint for a type that is "closable".
template <typename T>
concept IsClosable = requires(T t)
{
  { t.closeImplementation() } -> std::same_as<void>;
};

// I defer the constraint "IsClosable" to the function rather than the class
// otherwise when I use CRTP, the constraint would fail. 
template <typename T>
class Base
{
public:
  template <IsClosable C = T>
  void close()
  {
    static_cast<C*>(this)->closeImplementation();
  }
};

class Derived : public Base<Derived>
{
// Visibility in question here.
public:
  void closeImplementation()
  {

  }
};

I have attempted to trace what the compiler is actually seeing here. For simplicity I will remove the constraint. Doing so I have the following

  1. Restating the base code
template <typename T>
class Base
{
public:
  void close()
  {
    static_cast<T*>(this)->closeImplementation();
  }
};

class Derived : public Base<Derived>
{
// Visibility in question here.
public:
  void closeImplementation()
  {

  }
};
  1. The compiler first ignores the template declaration as nothing instantiates it yet.

  2. The compiler then comes across this line and starts to instantiate a template. Note that even though the full Derived class is not declared, this should be sufficient for template substitution.

class Derived : public Base<Derived>

leading to the following

template <>
class Base<Derived>
{
public:
  void close()
  {
    static_cast<Derived*>(this)->closeImplementation();
  }
};

I am not fully sure if this line makes sense just yet until we have the inheritance. It seems like before the inheritance takes place we are casting this which is a Base<Derived> base object to Derived which doesn't seem compatible.

  1. After the template is instantiated we then continue the declaration of the
class Derived : public Base<Derived>
{
// Visibility in question here.
public:
  void closeImplementation()
  {

  }
};

And if we substitute the methods we get from Base<Derived> this should more or less look like

class Derived // Inheriting from Base<Derived>
{
public:
  void closeImplementation()
  {

  }

  void close()
  {
    static_cast<Derived*>(this)->closeImplementation();
  }
};

So from this I have a few questions.

  1. Why can closeImplementation not be private if it "looks" like "close" can still access it?

  2. Does the line static_cast<Derived*>(this)->closeImplementation() get invoked in the Base<Derived> class or Derived? If it is the former, how does that work?

  3. Is my understanding of how the compiler views this code correct?