It looks like you're right, there's a bug in gcc
From §12.9 [class.inhctor]:
A using-declaration (7.3.3) that names a constructor implicitly declares a set of inheriting constructors. The
candidate set of inherited constructors from the class X
named in the using-declaration consists of actual
constructors and notional constructors that result from the transformation of defaulted parameters as follows:
- all non-template constructors of
X
So this means that your Derived
class should definnitely get a constructor from its base that accepts an int
. Following the normal rules of in-class member initialization, constructing an instance of Derived
shouldn't be a problem without a default constructor for Foo
because it's not being used. Hence, there's a bug in gcc:
§13.3.1.3 Initialization by constructor [over.match.ctor]
When objects of class type are direct-initialized (8.5) [...], overload resolution selects the constructor. For direct-initialization, the candidate
functions are all the constructors of the class of the object being initialized.
So the constructor Foo::Foo(int)
should have been selected, which it clearly wasn't in gcc.
One question I had after reading this was "Does this cause the default constructor for Derived
to be deleted?" The answer is no.
Conveniently, the standard provides an example below this excerpt (I'm excising what's not needed):
struct B1 {
B1(int);
};
struct D1 : B1 {
using B1::B1;
};
The set of constructors present in D1
is [Emphasis mine]
D1()
, implicitly-declared default constructor, ill-formed if odr-used
D1(const D1&)
, implicitly-declared copy constructor, not inherited
D1(D1&&)
, implicitly-declared move constructor, not inherited
D1(int)
, implicitly-declared inheriting constructor