C++ Logo

std-discussion

Advanced search

Re: inheriting initializer_list constructor fails with empty list

From: Svetlin Totev <svetli97_at_[hidden]>
Date: Tue, 28 May 2024 22:33:54 +0300
Ok so I finally understand the reasons why the error occurs:
B "doesn't have user-declared constructors" so the compiler has to create a
default constructor, but it becomes ill-formed because A doesn't have one.

11.4.5.2 Default constructors [class.default.ctor]
1. ... If there is no user-declared constructor for class X, a non-explicit
constructor having no parameters is implicitly declared as defaulted
([dcl.fct.def])...

So this would mean that the using-declaration "using A::A;" is not a
declaration of constructors. And yet it behaves exactly as user-declared
constructors except when asked the specific question: "are there any
user-declared constructors".

9.9 The using declaration [namespace.udecl]
13 Constructors that are named by a using-declaration are treated as though
they were constructors of the derived class when looking up the
constructors of the derived class ([class.qual]) or forming a set of
overload candidates ([over.match.ctor], [over.match.copy],
[over.match.list]).

So I suppose the wording of the rule about inheriting constructors only
talks about how they should be treated for constructor lookup and doesn't
explicitly call this a declaration of constructors word-for-word. So even
though it is a declaration of constructors explicitly done by the user,
there are no user-declared constructors.

This is an absurd and very counterproductive interpretation of the rules
that just adds yet another trap in the language and ruins the main use case
of inheriting constructors: to make the derived class have the same
constructors as the base class.
I'm sorry to say this but this language is unsalvageable. I spend 10x more
time fighting it than using it...

P.S.:

And the reason the initializer_list constructor isn't picked:

12.2.2.8 Initialization by list-initialization [over.match.list]
(1.1) If the initializer list is not empty or T has no default constructor,
overload resolution is first performed where the candidate functions are
the initializer-list constructors ([dcl.init.list]) of the class T and the
argument list consists of the initializer list as a single argument.

So B now has an ill-formed default constructor which has higher priority
than the initializer_list one.

On Tue, May 28, 2024 at 4:59 PM M.P. via Std-Discussion <
std-discussion_at_[hidden]> wrote:

> > B doesn't have a default constructor, just like A doesn't have one
>
> B has an implicitly-declared default constructor, see
> [class.default.ctor]/1.
>
> Adding a user-declared constructor to B suppresses the implicit
> declaration:
>
> #include <initializer_list>
>
> struct A { A(std::initializer_list<int>); };
> struct B : A {
> using A::A;
> B(void*);
> };
>
> A a {}; // ok
> B b {}; // ok
>
>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>

Received on 2024-05-28 19:34:07