19 Beginner The Hundred
The Initializer That Says No
two values shrink, and nothing stops them
#include <iostream>
int main() {
long total = 300;
int count = 3.9; // 3.9 of them, near enough
char code = total; // 300 is a small number
std::cout << "count = " << count << "\n";
std::cout << "code = " << static_cast<int>(code) << "\n";
}
Run it. What does it print — and what does the compiler have to say about it?
Answer
Not a peep from GCC, even with -Wall -Wextra. Swap = for {} and both lines draw a
diagnostic — the first one fatal.
Why¶
= initialization runs the old C conversion rules, which drop whatever does not fit:
double → int chops the fraction (3.9 becomes 3 — it never rounds) and long → char
keeps the low byte (300 becomes 44, the code for ','). Braced initialization, new in
C++11, refuses narrowing conversions — anything the type system cannot call
value-preserving — so the same two lines now draw the diagnostic the standard demands; try
-DSHOW_BUG:
error: narrowing conversion of '3.8999999999999999e+0' from 'double' to 'int' [-Wnarrowing]
warning: narrowing conversion of 'total' from 'long int' to 'char' [-Wnarrowing]
Mind the two severities: GCC 11.5 errors on the constant 3.9 but only warns on the
run-time total — a warning is still a conforming diagnostic, so add -Werror=narrowing
for a hard rejection (Clang 18.1 rejects both on its own). The rule judges types, not luck:
int n{total} is narrowing even though 300 fits in an int, while int n{300} is fine —
only constant integers get that pass, and even int n{3.0} is narrowing. -Wconversion
(in neither -Wall nor -Wextra) catches the = spellings too.
The fix¶
Initialize with braces — and when you really do want the loss, say so out loud, which also
forces you to decide which loss you meant (std::lround needs <cmath>):
int count{static_cast<int>(3.9)}; // 3 — truncation, on purpose
int rounded{static_cast<int>(std::lround(3.9))}; // 4 — rounding, on purpose
Takeaway: {} rejects the lossy conversions that = waves through — one more reason
to make braces your default.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo — then again with -DSHOW_BUG