When I use C++ template, I found that sometimes it gives a non-straightforward result.
#include <cstdlib>
#include <iostream>
template<class f0>
void func(const int& a1, f0& a2)
{
std::cout << a1 + a2 << '\n';
return;
}
template<class f0, class f1>
void func(f0& a1, f1& a2)
{
std::cout << a1 - a2 << '\n';
return;
}
int main(int argc, char *argv[])
{
int bb = 3;
int bbb = 3;
func(static_cast<const int &>(bb), bbb); // 6
func(bb, bbb); // 0
func((int)bb, bbb); // 6
func(static_cast<int &>(bb), bbb); // 0
func(static_cast<int>(bb), bbb); // 6
return 0;
}
When I pass an integer to first argument, It was recognized as a difference against const int &. However, when I re-pack it to int. I select the template of const int&.
I cannot find a good interpretation to explain the behavior. Does something have a suggestion for how it works?
TLDR;
(int)bbis explicit type conversion and the result is an prvalue and a non-const lvalue reference such asint&cannot be bound to an prvalue.Case 1
Here we consider the call
func((int)bb, bbb).Here the expression
(int)bbis a prvalue of typeint(and thus an rvalue) and since an rvalue cannot be bound to an lvalue reference to non-const type, the first overloadvoid func(const int& a1, f0& a2)is the only viable option here.That is, the first parameter
a1of the second overloadvoid func(f0& a1, f1& a2)is a non-const lvalue reference which cannot be bound to an rvalue and so the second overload is not viable. On the other hand, the first parametera1of the first overloadvoid func(const int& a1, f0& a2)is a const lvalue reference which can be bound to an rvalue and thus this first overload is viable and will be chosen.This can be seen from expr.cast#1:
(emphasis mine)
Case 2
Here we consider the call
func(static_cast<int>(bb), bbb);Here also the
static_cast<int>(bb)is a prvalue and thus the first overload is the only viable option.