Reputation: 70526
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
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