Per my understanding, for class type T
to be const-default-constructible type, the default-initialization of T
shall invoke a user-provided constructor, or T
shall provide a default member initializer for each non-variant non-static data member: ([dcl.init]/7)
A class type
T
is const-default-constructible if default-initialization ofT
would invoke a user-provided constructor ofT
(not inherited from a base class) or if
- (7.4) each direct non-variant non-static data member
M
ofT
has a default member initializer [..]
Noting the bold part, it seems to me that const-default-constructible types can only be class types (including unions and structs). Therefore I can't say that const int
, for example, is const-default-constructible type since int
is not a class type.
You might ask, from where this confusion comes. Basically, [class.default.ctor]/2 says:
A defaulted default constructor for class
X
is defined as deleted if:
- [..]
- (2.4) any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer is not const-default-constructible ([dcl.init]),
- [..]
Notice the word "any". This bullet considers cases where X
has data member M
, and M
is of class types as well as non-class types. But per [dcl.init]/7, the const-default-constructible types are limited to only be class types.
Consider the following example,
struct S
{
const int I;
// Is the type of S::I said to be non-const-default-constructible?
S() = default;
};
Is there missing wording? Am I misreading the quotes?
PS: Thanks to @463035818_is_not_a_number for clarifying this. Consider this case:
struct X
{
const int M = 0;
// Is the type of X::M said to be const-default-constructible?
X() = default;
};
CodePudding user response:
Is the type of S::I said to be non-const-default-constructible?
Yes. Like you've quoted in [dcl.init]/7 only class types can be const-default-constructible. The reason for this is non-class types do not have a default constructor, meaning they have no default value that can be used if they are declared like
const T foo;
When you read
any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer is not const-default-constructible ([dcl.init])
It is saying that if you have a member in the form of const T name;
in your class then the default constructor is deleted if T
is not const-default-constructible. In your case that means your constructor is deleted because const int
is not const-default-constructible.
In the case of X
, M
is still not const-default-constructible because it is not a class type. X
though is const-default-constructible because M
has a brace-or-equal-initializer so [class.default.ctor]/2.4 does not apply.
This can be boiled down into a simple rule: All const objects must have an initializer
Since built in types do not get default initialized they must have a value provided by the programmer.
CodePudding user response:
Non-class types are never const-default-constructible as you have read correctly.
But I don't think there is any wording missing. It seems intentional. The whole point of const-default-constructible is to make sure that you can't accidentally leave an object with an indeterminate value after initialization when you can't change that object's value later.
It would be UB to try to change the value of I
after initialization (because it is declared const
), but with the defaulted default constructor or without an explicit initializer on I
, it would be default-initialized to an indeterminate value (because that is the effect of default-initialization on non-class types) which then is impossible to change. An indeterminate value can be used for almost nothing. The standard doesn't even allow copying it (except for types unsigned char
and std::byte
).
So there is no reason to allow you to default-construct this S
with the defaulted default constructor.
(Technically the standard now allows using placement-new
to replace the I
object transparently as long as it is not part of a const-complete object, which allows changing its value in some sense, but that shouldn't be a normal use case.)