Search code examples
c++templatesinheritanceprivate-members

cpp: permit base member access only via derived by consumer


I have an application where Base is a factory class for objects that shall be created differently depending on a template pair. However, only very particular (countable infinite) number of template pairs make sense. For each of sensible pair, I have a (sometimes) templated Derived Factory class. The use of Base Factory is error prone due to the need for feasible correct choice of the template pair.

My question is: How can I prevent a consumer from using the Base Factory directly?

template<typename T1, typename T2>
class Base{
  Base()=delete;
public:
  // many public static routines
  T1 static foo(){ return 1; }
  T2 static bar(){ return 2; }
};

template<typename T1>
class Derived: public Base<T1,float>{
  // hopefully very little code, or none at all, as of now.
};

int main(){ // main is the consumer
  Base<int,float>::foo(); // prevent
  Derived<int>   ::foo(); // permit
}

I want the compiler to reject/thow/err the line with comment "prevent" in main. I want Base<..>::foo and Base<..>::bar not directly accessible by a consumer unless via access through Derived<..>. I had hoped that the virtual concept could be used for that purpose; however it does not transfer naturally from the non-static to the static case.


Solution

  • You can make the foo method protected, and expose it via the Derived class with a public using statement:

    template<typename T1, typename T2>
    class Base {
        Base() = delete;
    protected:
        T1 static foo() { return 1; }
        T2 static bar() { return 2; }
    };
    
    template<typename T1>
    class Derived : public Base<T1, float> {
    public:
        using Base<T1, float>::foo;
    };
    
    int main() { // main is the consumer
        Base<int, float>::foo(); // prevent
        Derived<int>   ::foo(); // permit
    }
    

    Live demo - Godbolt