Стандартное поведение для прямой инициализации беззнакового короткого замыкания
Сегодня я заметил, что в примере кода:
void print(unsigned short a) {
std::cout << a << std::endl;
}
Инициализация и использование работают следующим образом:
print(short (5));
Но не так:
print(unsigned short(6));
main.cpp: 16: 8: ошибка: ожидаемое первичное выражение перед печатью "unsigned" (unsigned short (6));
И это не связано с типом, так как это также работает:
typedef unsigned short ushort;
print(ushort (6));
Живой пример.
Поэтому я пошел искать то, что стандарт говорит о инициализации стоимости. Ничего не получается:
Эффект инициализации значения:
1) если T - тип класса...
2) если T - тип неединичного класса...
2) если T - тип класса...
3) если T - тип массива,..
4) в противном случае объект инициализируется нулем.
Модификации сделаны для удобочитаемости. Оригинальный источник.
Каковы правила инициализации значений типов POD? В чем причина того, что unsigned
квалифицированные типы не могут быть инициализированы значением? Это больше связано с тем, что они являются rvalues
?
Ответы
Ответ 1
В чем причина того, что unsigned
квалифицированные типы не могут быть инициализированы значением?
Это просто потому, что в функциональном выражении выражения можно использовать только однословное имя типа, а unsigned short
- не однотипное имя типа; short
есть.
Функциональное выражение выражений состоит из простого спецификатора типа или спецификатора typedef (другими словами, однотипное имя типа: unsigned int(expression)
или int*(expression)
недопустимы), за которым следует одно выражение в круглых скобках.
Как вы показали, вы можете использовать typedef
в качестве обходного пути или добавить круглые скобки, чтобы изменить его на c-style cast expression, например (unsigned short)(6)
или (unsigned short)6
.
Из стандарта, §7.6.1.3/1 Явное преобразование типа (функциональная нотация) [expr.type.conv]:
Спецификатор простого типа или спецификатор- имя -тип, за которым следует произвольный список выражений в скобках или в виде списка бит-инициализации (инициализатор), строит значение указанного типа с учетом инициализатора.
И простой тип-спецификатор:
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
Это просто сбой в грамматике: два имени типа слова не работают при создании временных объектов. То есть, ни одна из этих работ
template <typename T> void use(T);
int main() {
use(unsigned int());
use(const int());
use(long long());
}
Работа заключается в том, чтобы вместо этого использовать псевдоним для соответствующего типа, т.е. Все они работают:
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()); }
}
Скобки могут также использоваться для инициализации значения, хотя для этого требуется использование завитушек:
template <typename T> void use(T);
int main() {
use((unsigned int){});
use((const int){});
use((long long){});
}