In the CRTP pattern, we run into problems if we want to keep the implementation function in the derived class as protected. We must either declare the base class as a friend of the derived class or use something like this (I have not tried the method on the linked article). Is there some other (simple) way that allows keeping the implementation function in the derived class as protected?
Edit: Here is a simple code example:
template<class D> class C { public: void base_foo() { static_cast<D*>(this)->foo(); } }; class D: public C<D> { protected: //ERROR! void foo() { } }; int main() { D d; d.base_foo(); return 0; }
The above code gives error: ‘void D::foo()’ is protected
with g++ 4.5.1 but compiles if protected
is replaced by public
.
It's not a problem at all and is solved with one line in derived class:
friend class Base< Derived >;
#include <iostream> template< typename PDerived > class TBase { public: void Foo( void ) { static_cast< PDerived* > ( this )->Bar(); } }; class TDerived : public TBase< TDerived > { friend class TBase< TDerived > ; protected: void Bar( void ) { std::cout << "in Bar" << std::endl; } }; int main( void ) { TDerived lD; lD.Foo(); return ( 0 ); }
As lapk recommended, problem can be solved with simple friend class declaration:
class D: public C<D> { friend class C<D>; // friend class declaration protected: void foo() { } };
However, that exposes all protected/private members of derived class and requires custom code for each derived class declaration.
The following solution is based on the linked article:
template<class D> class C { public: void base_foo() { Accessor::base_foo(derived()); } int base_bar() { return Accessor::base_bar(derived()); } private: D& derived() { return *(D*)this; } // accessor functions for protected functions in derived class struct Accessor : D { static void base_foo(D& derived) { void (D::*fn)() = &Accessor::foo; (derived.*fn)(); } static int base_bar(D& derived) { int (D::*fn)() = &Accessor::bar; return (derived.*fn)(); } }; }; class D : public C<D> { protected: // Success! void foo() {} int bar() { return 42; } }; int main(int argc, char *argv[]) { D d; d.base_foo(); int n = d.base_bar(); return 0; }
PS: If you don't trust your compiler to optimize away the references, you can replace the derived()
function with the following #define
(resulted in 20% fewer lines of disassembly code using MSVC 2013):
int base_bar() { return Accessor::base_bar(_instance_ref); } private: #define _instance_ref *static_cast<D*>(this) //D& derived() { return *(D*)this; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With