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
longliteral instead of anintone at the callsite. So that__declval(long)is called without the need for an implicit conversion.
auto declval() noexcept -> decltype(__declval<_Tp>(0L));
