11
I’ve read this
Integral promotion:
prvalues of small integral types (such as char) may be converted to prvalues of larger integral types (such as int). – first line
[…details – not important…]
Note that all other conversions are not promotions; for example, overload resolution chooses char -> int (promotion) over char -> short (conversion). – final line.
The conversion from char -> int is ‘promotion’ ; it’s clear (from one byte to 4 bytes)
The conversion from char -> short is ‘not promotion’ ; why?
I’ve been thinking that char is one byte, and short (short int) is two bytes. Why isn’t it considered a promotion? It seems to contradict the first line – doesn’t it mean ‘convert from small type to bigger type’ is promotion? )
—–Edit: after looking for some answers:
Can we consider "a promotion is a special case of a conversion"? , can we say "all promotions are conversions, but not all conversions are promotions"?
Or should we consider them as 2 different and separate concepts?
4
4 Answers
Reset to default
11
Historical motivation: C
The idea of integral promotions dates all the way back to pre-standard C. When providing arguments to variadic functions (...
) or to functions without a prototype, promotions are applied. I.e. calling:
// function declaration with no prototype
void mystery();
// ...
char c = 'c';
mystery(c); // this promotes c to int
// in another .c file, someone could define
void mystery(int x) { /* ... */ }
Promotions are basically a "minimal" upgrade to the type, whereas conversions can be anything.
You could even argue that the design is a consequence of building on the B programming language, which didn’t even have multiple integer types like C does.
Relevant wording in the C++ Standard
The relevant paragraph in the standard C++ is:
A prvalue that is not a converted bit-field and has an integer type other than
bool
,char8_t
,char16_t
,char32_t
, orwchar_t
whose integer conversion rank is less than the rank ofint
can be converted to a prvalue of typeint
ifint
can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of typeunsigned int
.
The difference between promotions and conversions is explained here:
The conversions allowed as integral promotions are excluded from the set of integral conversions.
As you can see, there is some overlap between the two concepts, but any conversion which would also be a promotion is not considered a conversion.
Impact on overload resolution
As you’ve pointed out, char -> short
is a conversion, and char -> int
is a promotion.
This has a significant impact on overload resolution in some cases:
// A conversion sequence from char -> int is empty
// because char -> int it is a promotion, and so it doesn't contribute
// to the conversion sequence.
void f(int);
// A conversion sequence from char -> short has length 1
// because char -> short is not a promotion.
void f(short);
int main() {
// Not an ambiguous call; calls f(int), because the conversion sequence
// for this call is shorter.
// Note that in C, a character literal has type 'int', not 'char', so
// it is more symmetrical to favor 'int' whenever possible.
f('x');
}
If C++ was designed from scratch nowadays, promotions and conversions would likely be defined a lot differently, however, the status quo is what we have, and it’s unlikely to change.
Changing this behavior and wording after all these years is basically impossible because of how much code depends on it.
As with so many design decisions in C++, the answer is: historical reasons.
7
-
1
I expect to see your last code snippet on twitter in a few days. Holy hell, C++ never ceases to surprise me.
– julaine11 hours ago
-
@Jan Schultke: Can we consider "a promotion is a special case of a conversion"? , can we say "all promotions are conversions, but not all conversions are promotions"? Or should we consider them as 2 different and separate concepts?
– LiDa Cute11 hours ago
-
1
Hmm. I'm not sure, myself, but is an explicit conversion (i.e. with a cast) from a small integral type to an
int
still classified as promotion? Or is promotion only when the compiler 'does it itself'?– Adrian Mole11 hours ago
-
good question @AdrianMole
– LiDa Cute11 hours ago
-
1
@LiDaCute good question. I've updated the answer to explain that.
– Jan Schultke11 hours ago
7
Both char
to int
and char
to short
are conversions. Note the text’s use of “all other conversions” after discussing promotions: Promotions are a type of conversion.
A conversion is an operation that takes a value in one form and produces the same value (as nearly as possible) in another form:
- Taking a
char
value and producing anint
with the same value is a conversion. - Taking an
int
value and producing a string containing a decimal numeral representing the same value is a conversion. - Taking a weight in pounds and producing the same weight in kilograms is a conversion.
In many places in expressions, C++ automatically converts narrow integer types to wider integer types. This is done largely for historical purposes, and also because it could be awkward to do arithmetic purely in narrow types—char
arithmetic would overflow too easily, and requiring the programmer to explicitly insert casts to int
would make code cumbersome.
These special conversions are called “promotions.” The natural English meaning of the word, advancing to a higher position, fits these types of conversions: They all convert from a narrower type to a wider type (or to one at least as wide). Aside from that, the word is adopted to particularly designate these special conversions. An important feature of the integral promotions is they never change the value. (Ideally, no conversion would change a value, but this does happen due to constraints. One example is that converting a float
value of 3¼ to int
must produce an integer, so 3 is produced instead of 3¼. Another is that converting an int
value of −3 to unsigned
forces wrapping, so a value that is very different nominally is produced, although it does have a special relationship with the input value and can be considered the same value in modulo arithmetic.)
0
2
The C++ standard specifies a set of rules for integral promotions, and these rules are not solely based on the size of the types. The decision to promote a char
to an int
rather than a short
is based on the historical design of the language and the desire for consistent behavior across different platforms.
According to the C++ standard, integral promotions are defined to convert small integral types to a particular implementation-defined type, which is usually int
. Since int
is chosen as the target type for integral promotion, converting a char
to a short
doesn’t qualify as a promotion, even though short
is larger than char
. It falls under the category of conversions instead.
The specific rules can vary between different implementations and architectures, but this is the general reasoning behind the behavior you observed. It’s a part of the language’s design, guided by historical considerations and practical aspects of compiler implementation, rather than a strictly logical progression based on type size.
2
-
IIRC, it is possible for a
char
to be an unsigned 8-bit type (char
is guaranteed to be one byte) and also ashort
to be 8-bits (I think). Then, conversion between unsigned and signed types of the same size could result in an erroneous destination value. However, automatic integral promotion guarantees that the result is the same value as the original. (Note that this may be nonsense: The C++ Standard may dictate thatshort int
must be at least 16 bits … need to check!)– Adrian Mole11 hours ago
-
2
@AdrianMole: ,
short
indeed has a minimal range that requires 16 bits. Butchar
can be 16 bits too.sizeof
returns a multiple ofCHAR_BITS
. Sosizeof(short)==1
is still allowed.– MSalters11 hours ago
1
The short answer (sorry for the pun) is that’s just how it is defined.
Clearly going from char (1 byte) to short (2 bytes) should be a "safe" conversion (and so a "promotion"?). However, the referenced section specifically states what conversions are classified as "promotions", and short is not there. That’s just how it is. Why? Not sure – the text does say that arithmetic operators don’t accept operands smaller than an int, and so maybe it makes no sense to "promote" to a short, when it would only need to get promoted to int at some later time.
I think it's just a terminology quirk. Promotion comes as heritage from C language, by definition it converts a smaller type to
int
. Conversion is anything else that can be done implicitly (e.g. char -> short, or int -> bool, or like when you define some custom conversion operator to bool, etc)11 hours ago
Don't get too tied up with the actual sizes of various integral types. Even if
short
andint
have the same bit-width (which is allowed), they have different ranks. And only the basicint
type is used in 'automatic' promotions.11 hours ago
Well, every C++ theory is a mystery to me. I seem to never get out a lesson without being confused
11 hours ago
Historically,
int
is special, being the "native" integral type (e.g. with all operations implemented with dedicated hardware instructions) so more efficient to convert smaller integral types (likeshort
andchar
) toint
and doing operations rather than using instructions directly on the smaller types. This history is (part of) why integral types have ranks in C and C++, and why "promotions" toint
are distinguished other integral conversions. The distinction is less important (or unimportant!) with modern processors, but supports compatibility with systems where it still matters.11 hours ago