Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Standard behavior for direct initialization of unsigned short

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?

like image 451
Fantastic Mr Fox Avatar asked Aug 17 '18 10:08

Fantastic Mr Fox


People also ask

What are the properties of the unsigned short int data type?

Some properties of the unsigned short int data type are: 1 Being an unsigned data type, it can store only positive values. 2 Takes a size of 16 bits. 3 A maximum integer value that can be stored in an unsigned short int data type is typically 65535, around 216 – 1 (but is compiler dependent ). More items...

What are the effects of direct initialization?

The effects of direct initialization are: The program is ill-formed The array is initialized as in aggregate initialization, except that narrowing conversions are allowed and any elements without an initializer are value-initialized .

What is the minimum value that can be stored in unsigned int?

The minimum value that can be stored in unsigned short int is zero. In case of overflow or underflow of data type, the value is wrapped around. For example, if 0 is stored in an unsigned short int data type and 1 is subtracted from it, the value in that variable will become equal to 65535.

What is direct initialization in C++?

Direct initialization is performed in the following situations: 2) initialization of an object of non-class type with a single brace-enclosed initializer (note: for class types and other uses of braced-init-list, see list-initialization) The effects of direct initialization are: The program is ill-formed


2 Answers

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) or int*(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
like image 107
songyuanyao Avatar answered Sep 30 '22 20:09

songyuanyao


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){});
}
like image 45
Dietmar Kühl Avatar answered Sep 30 '22 20:09

Dietmar Kühl