Стандартное поведение для прямой инициализации unsigned short

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

void print(unsigned short a) {
   std::cout << a << std::endl;
}

Инициализация и использование работает следующим образом:

print(short (5));

но не такой:

print(unsigned short(6));

main.cpp: 16: 8: Ошибка: ожидаемое первичное выражение перед "unsigned" print (unsigned short (6));

и это не связано с типом, так как это также работает:

typedef unsigned short ushort;
print(ushort (6));

живой пример.

поэтому я пошел искать то, что стандарт говорит об инициализации значения. Получается ничего:

эффекты инициализации значения:

1) Если T-тип класса ...

2) Если T-тип класса без объединения ...

2) Если T-тип класса ...

3) Если T-тип массива,..

4) иначе, объект инициализирован нулем.

модификации для удобочитаемость. первоисточник.

каковы правила инициализации значения POD типы? В чем причина того, что unsigned квалифицированные типы не могут быть инициализированы значением? Это связано с тем, что они являются rvalues?

2 ответов


в чем причина этого unsigned квалифицированные типы не могут быть инициализированы значением?

это просто потому, что в функциональное выражение cast, а unsigned short не является именем типа одного слова;short есть.

функциональное выражение cast состоит из простого спецификатора типа или спецификатора typedef (другими словами, однословное имя типа:unsigned int(expression) или int*(expression) не действительны), далее следует одно выражение в скобках.

как вы показали, вы можете использовать typedef в качестве обходного пути или добавьте скобки, чтобы изменить его на выражение C-style cast, например (unsigned short)(6) или (unsigned short)6.

из стандартного, §7.6.1.3 / 1 явное преобразование типов (функциональная нотация) [expr.тип.conv]:

A простой-тип-описатель или параметр typename-описатель после чего в скобках необязательный expression-list или braced-init-list (инициализатор) создает значение указанного типа, заданного инициализатором.

и простой-тип-описатель:

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-описатель:

typename-specifier:
  typename nested-name-specifier identifier
  typename nested-name-specifier template opt
 simple-template-id

это просто сбой в грамматике: два имени типа слов не работают при создании временных объектов. То есть ни одна из этих работ

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