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 ?
CodePudding user response:
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
CodePudding user response:
A quirk of built-in operators is that they will perform integral promotion on small arguments:
cppreference on implicit conversions:
prvalues of small integral types (such as
char
) may be converted to prvalues of larger integral types (such asint
). In particular, arithmetic operators do not accept types smaller thanint
as arguments, and integral promotions are automatically applied after lvalue-to-rvalue conversion, if applicable. This conversion always preserves the value.
In your code's case, the bitwise OR operator is promoting your uint16_t
s to int
before applying the operator.