That function template with a return type of
int_precision&& returns a dangling reference. It is always undefined behavior to access its result.
Don't return references from functions for no reason, but even if there is a reason, in every case there must be a guarantee that the referent is still within its lifetime when the function returns. Do not return references to local variables and do not return references to temporary objects.
Back on topic, consider this program:
1 2 3 4 5 6 7
|
void f(long, int) {}
void f(int, long) {}
int main()
{
f(0, 0);
}
| |
Ultimately this asks the compiler to choose between a call to
void f(int, long)
and a call to
void f(long, int)
where both arguments have type
int.
- To call the first overload, the first argument must undergo a type conversion from
int to
long.
- To call the second overload the second argument must undergo a type conversion from
int to
long.
The compiler can't choose which argument to convert, so it complains.
Now look at this program which more closely corresponds to the actual case:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
struct ostream {};
struct ofstream: ostream {};
struct int_precision { int_precision(int) {}; };
// First overload corresponds to `operator<<` in the standard namespace
void ambiguous(ostream&, int) {};
// Second overload corresponds to template `operator<<` in iprecision.h
template <typename T>
void ambiguous(T&, int_precision);
int main()
{
ostream cout;
ofstream fout;
ambiguous(fout, 1);
}
| |
This is asking the compiler to choose between a call to
void ambiguous(ostream&, int);
and
void ambiguous(ofstream&, int_precision);
This second function signature is the candidate function the compiler considers after performing template argument deduction.
Like in the prior example,
- To call the first overload, the first argument must undergo a type conversion from
ofstream to
ostream, the type of its base class.
- To call the second overload, the second argument must undergo a type conversion from
int to
int_precision, which is made possible via
int_precision's converting constructor.
The compiler still can't choose which argument to convert, so it complains.