Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

unexpected behavior with template function overloading

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

: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?

>Solution :

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:

  1. Make sure there is only one overload that is implicitly callable from an int. That’s how the original snippet works.

  2. Provide an overload that does not need an implicit conversion for the parameter used at the callsite. This is what using __declval(int) does.

  3. Use a long literal instead of an int one at the callsite. So that __declval(long) is called without the need for an implicit conversion.

auto declval() noexcept -> decltype(__declval<_Tp>(0L));
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading