TemplateRex
TemplateRex

Reputation: 70526

Is an inherited default constructor also user-defined?

The Clang documentation neatly explains that

If a class or struct has no user-defined default constructor, C++ doesn't allow you to default construct a const instance of it like this ([dcl.init], p9)

The following code has such a user-defined default constructor for Base, but g++ and Clang disagree whether the default constructor for Derived is user-defined, even though Derived does explicitly inherit all of the Base constructors (using the new C++11 inheriting constructors feature)

#include <iostream>

class Base
{
public:
    Base(): b_(0) {}  // look! user-defined default constructor
    void print() const { std::cout << b_ << "\n"; }
private:
    int b_;
};

class Derived
:
    public Base
{
    using Base::Base; // does this constitute a user-defined default constructor?
};

int main()
{
    Base const b;
    b.print();    // 0 for g++ & CLang

    Derived const d;
    d.print();    // 0 for g++, Clang: "default initialization of an object of const type 'const Derived' requires a user-provided default constructor"
}

g++ 4.8 happily accepts this code, but Clang 3.3 does not. What does the Standard say?

NOTE: without a user-defined default constructor for Base, neither g++ 4.8 nor Clang 3.3 accept Base const b; (whereas e.g. g++ 4.7.2 previously accepted that). Given that g++ knows about the rule, I would think that this implies that g++ regards the default constructor for Derived as user-defined. But Clang 3.3 thinks otherwise.

UPDATE: based on @JesseGood 's answer that 0/1 argument constructors are never inherited, I tried changing the Base constructor to

Base(int b = 0, void* = nullptr): b_(b) {}

but it does not resolve the Clang error.

Upvotes: 13

Views: 632

Answers (1)

Jesse Good
Jesse Good

Reputation: 52365

Clang is correct.

The relevant passage about const instances is from 8.5p7:

If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.

Since Base(): b_(0) {} is user-provided, Base const b; is fine.

The next important part is 12.9p3:

For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears

The important part here is the bolded text. I believe this rules out your case since Base() is a constructor having no parameters. This means that the Derived does not have a user provided default constructor (although one still is implicitly declared).

What this also means is that default, copy and move constructors from a base class are never inherited.

Upvotes: 7

Related Questions