Стандартное поведение для прямой инициализации беззнакового короткого замыкания

Сегодня я заметил, что в примере кода:

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){});
}