C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Is a default ctor struct C{C(); }; also a converting constructor

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Tue, 9 Jan 2024 14:08:57 -0500
On Tue, Jan 9, 2024 at 1:11 PM connor horman via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> There's no copy-constructor call, though (not even an elided one, I
> believe copy-init from RHS of declarator never even tried to call a copy or
> move constructor).
> copy-list-init doesn't call the copy constructor, it calls the list-init
> eligible converting constructor. It's converting from the empty initializer
> list, not a value constructed C.
>

Yes, and... (for Sean's further benefit)
In C++11-and-later, `{...}` denotes what I often call a "bag of arguments"
— "given these arguments, implicitly convert them to the-thing-you-need on
the LHS."
    std::pair<int, int> p1 = {1,2}; // "Given 1 and 2, make a pair"
    std::pair<int, int> p2 = {std::piecewise_construct,
std::forward_as_tuple(1), std::forward_as_tuple() }; // "Given these three
arguments, make a pair"
    std::pair<int, int> p3 = {}; // "Given nothing at all, make a pair"
The bag *is* allowed to be empty — as you see in `p3`'s initializer.

As a type author, if you have a class that's intended to be initialized
from a sequence of *zero or more* elements, then you should give it a
converting initializer-list constructor *and also* a converting default
constructor, because (for historical reasons that might or might not make
sense anymore) it's the default ctor that's going to be called in the
zero-element scenario.
    std::vector<int> v1 = {}; // OK, converting default ctor
    std::vector<int> v2 = {1}; // OK, converting initializer-list ctor

If you have a class that's *not* intended to be initialized from an empty
sequence (an empty bag of arguments), then you *shouldn't* give it a
converting default constructor; you should make its default constructor
`explicit` instead.
    Cat c1 = {}; // OK if the author wrote `Cat() = default`, but I hope
they didn't
    Cat c2 = Cat(); // always OK, even if the author wrote `explicit Cat()
= default` as I hope they did

The waters are quite muddied by the fact that the STL doesn't use this
convention; the STL very consistently (but, from a green-field point of
view, unwisely) makes all its constructors be converting constructors
*except* for most single-argument constructors and in a very few ad-hoc
other cases.

Related:
https://quuxplusone.github.io/blog/2023/04/08/most-ctors-should-be-explicit/

Cheers,
Arthur

Received on 2024-01-09 19:09:10