Home > database >  Inheriting constructors with initializer_list from multiple base classes deletes constructor
Inheriting constructors with initializer_list from multiple base classes deletes constructor

Time:07-13

Apparently my compiler deletes my constructor for reasons I can't understand.

Compare this: This is working (Compiler Explorer):

using val = std::variant<std::monostate, int, bool>;

struct keyval
{
    keyval(std::string, int) {

    }
};

struct base_A
{
    base_A(std::initializer_list<val>) {
        
    }
};

struct base_B
{
    base_B(std::initializer_list<keyval>) {
        
    }
};

struct derived : public base_A//, public base_B
{
    using base_A::base_A;
    // using base_B::base_B;
};

int main() {
    derived D = {1,2,3,4, true};
}

But if you uncomment it's not working anymore (CompilerExplorer)!

Apparently my compiler decided to delete the variant constructor inherited from base_A because it would be ill-formed. But how so if it worked before?

<source>:34:31: error: use of deleted function 'derived::derived(std::initializer_list<std::variant<std::monostate, int, bool> >) [inherited from base_A]'
   34 |     derived D = {1,2,3,4, true};
      |   

CodePudding user response:

As per cppref:,

If overload resolution selects one of the inherited constructors when initializing an object of such derived class, then the Base subobject from which the constructor was inherited is initialized using the inherited constructor, and all other bases and members of Derived are initialized as if by the defaulted default constructor (default member initializers are used if provided, otherwise default initialization takes place).

Other base classes are required to be default constructed (and only one default constructor otherwise resolution will be ambiguous).

In your case, how does the compiler know how to correctly initialize base_B since you don't provide a default constructor for it?

A simple fix is to make a default constructor for base_B.

struct base_B
{
    base_B(std::initializer_list<keyval> = {}) {}
};

or

struct base_B
{
    base_B(std::initializer_list<keyval>) {}
    base_B() {}
};

Demo

  • Related