Consider the following code:
#include <iostream>
float func(char const & val1, unsigned int const & val2)
{
return val1 + val2;
}
int main() {
double test1 = 0.2;
double test2 = 0.3;
std::cout << func(test1, test2) << std::endl;
return 0;
}
This compiles and runs despite the fact that I am passing in a double
to a function that takes a const-reference to types that are smaller than a double
(on my system, sizeof(double) == 8
, while sizeof(unsigned int) == 4
, and sizeof(char) == 1
by definition). If the reference isn't const
, compilation fails (e.g., float func(char & val1, unsigned int & val2)
instead of the current definition) with an error:
cannot bind non-const lvalue reference of type 'char&' to an rvalue of type 'char'
I get the exact same behavior when testing this with GCC, Clang, ICC, and MSVC on Godbolt, so it appears standard. What is it about const-references that causes this to be accepted, whereas a reference isn't? Also, I used -Wall -pedantic
- why am I not getting a warning about a narrowing conversion? I do when the function passes by value instead of by reference...
It is indeed standard.
test1
and test2
are converted to anonymous temporary char
and unsigned
types for which the const
references in the function are appropriate bindings. If you set your compiler to warn you of narrowing conversions (e.g. -Wconversion), it would output a message.
These bindings are not possible if the function parameters are non-const
references, and your compiler is correctly issuing a diagnostic in that case.
One fix is to delete
a better overload match:
float func(double, double) = delete;