问题
I noticed today that in the example code:
void print(unsigned short a) {
std::cout << a << std::endl;
}
Initialization and use works like this:
print(short (5));
But not like this:
print(unsigned short(6));
main.cpp:16:8: error: expected primary-expression before 'unsigned' print(unsigned short(6));
And it's not to do with the type since this also works:
typedef unsigned short ushort;
print(ushort (6));
Live example.
So I went searching for what the standard says about value initialization. It turns out nothing:
The effects of value initialization are:
1) if T is a class type ...
2) if T is a non-union class type ...
2) if T is a class type ...
3) if T is an array type, ..
4) otherwise, the object is zero-initialized.
Modifications made for readability. Original source.
What are the rules about value initialization of POD types? What is the reason that unsigned
qualified types can't be value initialized? Is this more to do with the fact they are rvalues
?
回答1:
What is the reason that
unsigned
qualified types can't be value initialized?
It's just because only single-word type name could be used in functional cast expression, while unsigned short
is not a single-word type name; short
is.
The functional cast expression consists of a simple type specifier or a typedef specifier (in other words, a single-word type name:
unsigned int(expression)
orint*(expression)
are not valid), followed by a single expression in parentheses.
As you showed, you can use typedef
as the workaround, or add parentheses to change it to c-style cast expression, e.g. (unsigned short)(6)
, or (unsigned short)6
.
From the standard, §7.6.1.3/1 Explicit type conversion (functional notation) [expr.type.conv]:
A simple-type-specifier or typename-specifier followed by a parenthesized optional expression-list or by a braced-init-list (the initializer) constructs a value of the specified type given the initializer.
And simple-type-specifier:
simple-type-specifier: nested-name-specifier opt type-name nested-name-specifier template simple-template-id nested-name-specifier opt template-name char char16_t char32_t wchar_t bool short int long signed unsigned float double void auto decltype-specifier type-name: class-name enum-name typedef-name simple-template-id decltype-specifier: decltype ( expression ) decltype ( auto )
typename-specifier:
typename-specifier: typename nested-name-specifier identifier typename nested-name-specifier template opt simple-template-id
回答2:
That's just a glitch in the grammar: the two word type names don't work when creating temporary objects. That is, none of these work
template <typename T> void use(T);
int main() {
use(unsigned int());
use(const int());
use(long long());
}
The work-around is to use an alias for the respective type instead, i.e., all of these do work:
template <typename T> void use(T);
int main() {
{ using type = unsigned int; use(type()); }
{ using type = const int; use(type()); }
{ using type = long long; use(type()); }
}
Parenthesis can also be used for value initialisation although the require the use of curlies:
template <typename T> void use(T);
int main() {
use((unsigned int){});
use((const int){});
use((long long){});
}
来源:https://stackoverflow.com/questions/51893895/standard-behavior-for-direct-initialization-of-unsigned-short