Search code examples
c++type-conversionbitwise-operatorsinteger-promotionbitwise-or

The type returned by 'operator|' does not always match the type you passed it


Some code called a templated function, but it did not call the specialisation I expected. Turned out the culprit was this: I or-ed some uint16_t constants and passed them as an argument like this: foo(uint16_bar | uint16_baz);. My expectation was it would call the foo<uint16_t>, but it did not. I can easily evade the problem with a cast, but I really wonder what the reason for this might be. Especially since not every integral type you pass it will return type int.

Case 1:

uint16_t a = 2;
uint16_t b = 4;
auto x = (a|b); // x is of type 'int': Surprize!

Case 2:

uint a = 2;
uint b = 4;
auto x = (a|b); // x is of type unsigned_int: What I would expect

Why does (a|b) in case 1 not return a value of type uint16_t ?


Solution

  • The usual arithmetic conversions are applied to operands of the bitwise operator |. That means that integer objects of types with rank less than the rank of the type int are converted either to int or unsigned int due to the integral promotions that are a part of the usual arithmetic conversions..

    From the C++ 14 Standard ( 5.13 Bitwise inclusive OR operator)

    1 The usual arithmetic conversions are performed; the result is the bitwise inclusive OR function of its operands. The operator applies only to integral or unscoped enumeration operands.

    and (4.5 Integral promotions)

    1 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