Search code examples
c++c++11autointeger-promotion

Why auto is deduced to int instead of uint16_t


I have the following code:

uint16_t getLastMarker(const std::string &number);
...
const auto msgMarker = getLastMarker(msg.number) + static_cast<uint16_t>(1);
static_assert(std::is_same<decltype(msgMarker), const int>::value, "Should fail");
static_assert(std::is_same<decltype(msgMarker), const uint16_t>::value, "Should not fail");

and I expect that the first assertion will fail and second one will not. However gcc 4.9.2 and clang 3.6 do the opposite. If I use uint16_t instead of auto in my code proper assertion fails and another one succeeds.

P.S. Initially I had just 1 instead of static_cast<uint16_t>(1) and thought that the issue is caused by the fact that numeric literal 1 has type int but wrong assertion fails even after explicit cast here.


Solution

  • Addition will perform the usual arithmetic conversions on its operands which in this case will result in the operands being promoted to int due the the integer promotions and the result will also be int.

    You can use uint16_t instead of auto to force a conversion back or in the general case you can use static_cast.

    For a rationale as to why type smaller than int are promoted to larger types see Why must a short be converted to an int before arithmetic operations in C and C++?.

    For reference, from the draft C++ standard section 5.7 Additive operators:

    [...]The usual arithmetic conversions are performed for operands of arithmetic or enumeration type[...]

    and from section 5 Expressions:

    [...]Otherwise, the integral promotions (4.5) shall be performed on both operands.59 Then the following rules shall be applied to the promoted operands[...]

    and from section 4.5 Integral promotions (emphasis mine):

    A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

    Assuming int is larger than 16-bit.