CRTP with Protected Derived Member

前端 未结 3 720
半阙折子戏
半阙折子戏 2021-01-30 11:19

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

3条回答
  •  遇见更好的自我
    2021-01-30 11:29

    As lapk recommended, problem can be solved with simple friend class declaration:

    class D:  public C {
        friend class C;      // 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 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 {
    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(this)   //D& derived() { return *(D*)this; }
    

提交回复
热议问题