Is it possilbe to inherit private constructors with using in cpp >= 11

Viewed 116

Is there a way to inherit private constructors with the using statement? I tried adding a friend statement, but it did not seem to work.

struct B;
struct A
{
private:
    A(int x) {}
    A(int y, double z) {}
    friend struct B;
};
struct B : public A
{
public:
    using A::A;
    //B(int x) : A(x) {}
    //B(int x, int y) : A(x, y) {}
};
void demo()
{
    B b1(5); // does not compile - implicit constructor is not accessible 
    B b2(4, 9.0);
}

I wonder if there is any way to do it with using, since if I explicitly create the delegating constructors the friend statement works, so this seams inconsistent:

struct B;
struct A
{
private:
    A(int x) {}
    A(int y, double z) {}
    friend struct B;
};
struct B : public A
{
public:
    B(int x) : A(x) {} // OK
    B(int x, int y) : A(x, y) {}
};

void demo()
{
    B b1(5); // OK 
    B b2(4, 9.0);
}
3 Answers

Accessibility of inherited constructors is not affected by the accessibility of the using declaration that introduces them.

[namespace.udecl] (emphasis mine)

19 A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored.

Since you can't access the constructor of A in main, it isn't accessible to construct a B in main either (you would be able to use it in order to construct B's and A's inside the scope of B though, on account of the friendship). You'll need to spell out some sort of of forwarding c'tor explicitly for outside-the-class access. Since you seem to be after a "catch-all", a fairly simple solution can be

template<typename... Args>
B(Args&&... args) : A(std::forward<Args>(args)...) {}

I wonder if there is any way to do it with using, since if I explicitly create the delegating constructors the friend statement works

No, when using the base class constructors, they will keep the original protected or private access, so you need to implement them in the derived class if you'd like to make them public. Making B a friend doesn't change that. It only allows B to access the private members in A - both functions and variables.

If you'd like derived classes to be able to use certain private member functions, you usually make those member functions protected instead.

struct A {
protected:
    A(int x) {}
    A(int y, double z) {}
};

struct B : public A {
public:
    B(int x) : A(x) {}
    B(int y, double z) : A(y, z) {}
};

With this, you don't need to know about the derived classes when designing A and you also keep your private member variables in A private.

Based on @StoryTeller - Unslander Monica's answer, which explains that the (inherited) constructors are accessible where the base class constructors would be, here is a very partial solution which will work in some cases:

struct A
{
private:
    A(int x) {};
    A(int y, double z) {};
    friend struct B;
};
struct B : public A
{
public:
    friend void demo();
    using A::A;
};

void demo()
{
    B b1(5);
    B b2(4, 9.0);
}

int main() {
    demo();
}
Related