Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between `std::default_initializable` and `std::is_default_constructible`?

Tags:

c++

c++20

C++20 adds a concept called std::default_initializable. The difference in naming compared to std::is_default_constructible seems to be way too obvious to be accidental.

Their specifications are worded differently as well (at least on cppreference), however I don't understand what the effective differences are.

Here's a short summary of the cppreference articles:

std::is_default_constructible<T> requires T foo(); to be well-formed, with the assumption that it's not parsed as a function declaration. In other words (if I understand correctly), T needs to be destructible and T() needs to be well-formed.
(edit: it doesn't seem to require destructibility, so here's the first difference)

std::default_initializable, on the other hand, requires both T foo;, T() and T{} to be well-formed.

Are there any effective differences between those two?

As far as I know, T{} is always interpreted as T() (ignoring most vexing parse, which doesn't count here), so I'm not sure why it's mentioned explicitly. Also T() being well-formed seems to imply T foo; being well-formed.

like image 741
HolyBlackCat Avatar asked Jun 25 '20 14:06

HolyBlackCat


2 Answers

This is basically LWG 3149:

DefaultConstructible<T> is equivalent to Constructible<T> (18.4.11 [concept.constructible]), which is equivalent to is_constructible_v<T> (20.15.4.3 [meta.unary.prop]). Per 20.15.4.3 [meta.unary.prop] paragraph 8:

The predicate condition for a template specialization is_­constructible<T, Args...> shall be satisfied if and only if the following variable definition would be well-formed for some invented variable t:

T t(declval<Args>()...);

DefaultConstructible<T> requires that objects of type T can be value-initialized, rather than default-initialized as intended.

The motivation for the concept is to check if you can write:

T t;

But the definition doesn't check that, it checks if you could write T(). But T() also doesn't mean that you can write T{} - there are types for which those have different meaning:

struct S0 { explicit S0() = default; };
struct S1 { S0 x; }; // Note: aggregate
S1 x;   // Ok
S1 y{}; // ill-formed; copy-list-initializes x from {}

And the intent is to simplify, for the sake of sanity, what the library has to deal with so we want to reject S1 as just being weird.


And then once the concept is checking something different from is_default_constructible, LWG 3338 renamed it. Since, different things should have different names.

like image 186
Barry Avatar answered Oct 21 '22 09:10

Barry


LWG issue 3338

  • 3338. Rename default_constructible to default_initializable

highlights a difference in meaning between the is_default_constructible trait and the C++20 concept originally named default_constructible, were LWG issue 3149 to be accepted:

3149 DefaultConstructible should require default initialization

Discussion

[...] [the concept] DefaultConstructible<T> requires that objects of type T can be value-initialized, rather than default-initialized as intended.

The library needs a constraint that requires object types to be default-initializable. [...]

Users will also want a mechanism to provide such a constraint, and they're likely to choose DefaultConstructible despite its subtle unsuitability.

Tim Song provided an example as for when the requirement of "can be value-initialized" is too weak as compared to the stricter requirement of "can be default initialized".

Tim Song noted that {} is not necessarily a valid initializer for a DefaultConstructible type. In this sample program (see Compiler Explorer):

struct S0 { explicit S0() = default; };
struct S1 { S0 x; }; // Note: aggregate
S1 x;   // Ok
S1 y{}; // ill-formed; copy-list-initializes x from {}

S1 can be default-initialized, but not list-initialized from an empty braced-init-list. The consensus among those present was that DefaultConstructible should prohibit this class of pathological types by requiring that initialization form to be valid.

Issue 3149 has has since been moved to status WP (essentially accepted save for as a Technical Corrigendum).

Issue 3338 has subsequently also been given WP status, renaming the default_constructible concept to default_initializable:

3338. Rename default_constructible to default_initializable

Discussion

[...] It was made clear during discussion in LEWG that 3149 would change the concept to require default-initialization to be valid rather than value-initialization which the is_default_constructible trait requires. LEWG agreed that it would be confusing to have a trait and concept with very similar names yet slightly different meanings [...].

Proposed resolution:

[...] Change the stable name "[concept.defaultconstructible]" to "[concept.default.init]" and retitle "Concept default_constructible" to "Concept default_initializable". Replace all references to the name default_constructible with default_initializable (There are 20 occurrences).

like image 35
dfrib Avatar answered Oct 21 '22 07:10

dfrib