So i have the following snippet which compiles correctly:
template<typename _Tp, typename _Up = _Tp&&>
_Up
__declval(long);
//template<typename _Tp>
// _Tp
// __declval(char);
template<typename _Tp>
auto declval() noexcept -> decltype(__declval<_Tp>(0));
int main()
{
declval<int>;
return 0;
}
and i have this one, which for some reason it doesn't:
template<typename _Tp, typename _Up = _Tp&&>
_Up
__declval(long);
template<typename _Tp>
_Tp
__declval(char);
//but if we change char to int it works
template<typename _Tp>
auto declval() noexcept -> decltype(__declval<_Tp>(0));
int main()
{
declval<int>;
return 0;
}
The error i get with the second snippet according to clang:
:26:5: error: reference to overloaded function could not be resolved; did you mean to call it?
But when i replace the __declval(char) with __declval(int) the error disappears. I've been scratching my head for some time now, any clues about the underlying cause of this issue?
CodePudding user response:
You are running into effectively the same problem as the following, simpler and equally broken, program:
void foo(long) {}
void foo(char) {}
int main() {
foo(0);
}
The error is a lot clearer here though:
:5:5: error: call to 'foo' is ambiguous
The issue is that 0
, being an int
, is equally valid as a char
as it is as a long
. In both cases, an implicit conversion is required. Since neither is preferable to the other, the call is ambiguous.
There are 3 ways to fix this:
Make sure there is only one overload that is implicitly callable from an
int
. That's how the original snippet works.Provide an overload that does not need an implicit conversion for the parameter used at the callsite. This is what using
__declval(int)
does.Use a
long
literal instead of anint
one at the callsite. So that__declval(long)
is called without the need for an implicit conversion.
auto declval() noexcept -> decltype(__declval<_Tp>(0L));