How to force use a curiously repeating template pattern in C ++

I have the following base template class.

template<typename T> class Base { public: void do_something() { } }; 

It is intended to be used as a curiously repeating pattern template. It should be inherited as class B : public Base<B> . It should not be inherited like class B : public Base<SomeoneElse> . I want to statically apply this requirement. If someone uses this incorrectly, I expect an error at the compilation stage.

What I am doing is putting static_cast<T const&>(*this) in do_something() . Thus, the class that inherits the template is inherited or inherited from the class provided as the template parameter. Sorry for the confusing expression. In plain English, it requires B be or inherited from SomeoneElse in class B : public Base<SomeoneElse> .

I do not know if this is optimal for this. It looks rude to me.

However, I want to do more. I want B be SomeoneElse myself. How can i do this?

+6
source share
3 answers

Make the Base constructor (or destructor) private, and then make T a friend . So the only thing that can build / destroy Base<T> is T

+8
source

If your class contains code that says:

 T* pT = 0; Base *pB = pT; 

Then there will be a compiler error if T not compatible with the Base assignment.

This type of validation is formalized in C ++ 11, so you do not need to write it manually and can receive useful error messages:

 #include <type_traits> template<typename T> class Base { public: void do_something() { static_assert( std::is_base_of<Base, T>::value, "T must be derived from Base"); } }; class B : public Base<B> { }; int main() { B b; b.do_something(); } 

As for the fact that the Base type parameter is exactly the class that derives from it, this seems conceptually erroneous. A class acting as a base class cannot "talk" about which type inherits it. It can be inherited more than once through multiple inheritance or is completely absent.

+3
source

Two good answers so far. Here is another one that uses the idiom of generating custom access keys to specific methods (in this case, the constructor). It provides an absolute guarantee of proper use without exposing private methods to derivatives in the database.

It can also be used to control access to other methods of the base class in each case.

 template<class Derived> struct Base { private: // make constructor private Base() = default; protected: // This key is protected - so visible only to derived classes class creation_key{ // declare as friend to the derived class friend Derived; // make constructor private - only the Derived may create a key creation_key() = default; }; // allow derived class to construct me with a key Base(creation_key) {} // other methods available to the derived class go here private: // the rest of this class is private, even to the derived class // (good encapsulation) }; struct D1 : Base<D1> { // provide the key D1() : Base<D1>(creation_key()) {} }; 
+1
source

Source: https://habr.com/ru/post/987183/


All Articles