Subject: Re: [boost] C++11 decltype/SFINAE puzzler
From: Andrew Sutton (asutton.list_at_[hidden])
Date: 2012-07-06 16:15:41


> So, my question is: what can be done about this? Can we get the benefit
> of automatic type deduction in return types without causing SFINAE to
> drop functions from the overload set? Is there another trick we can use
> to report errors meaningfully when APIs are misused?

No!

Just kidding. I was actually wondering something very similar earlier
today. How can we intelligently document the causes of SFINAE-based
overloading errors? I don't have a good answer yet.

But I plugged in the problem you mentioned and checked it out with GCC
4.8 (compiled from trunk a month ago -- has it been so long?).

template <typename T>
  auto h(T x) -> decltype(*x) { return *x; }

template <typename T>
  auto g(T x) -> decltype(h(x)) { return h(x); }

template <typename T>
  auto f(T x) -> decltype(g(x)) { return g(x); };

int main()
{
  f(0);
}

And get this as output:

foo.cpp: In function ‘int main()’:
foo.cpp:22:6: error: no matching function for call to ‘f(int)’
   f(0);
      ^
foo.cpp:22:6: note: candidate is:
foo.cpp:18:8: note: template<class T> decltype (g(x)) f(T)
   auto f(T x) -> decltype(g(x)) { return g(x); };
        ^
foo.cpp:18:8: note: template argument deduction/substitution failed:
foo.cpp: In substitution of ‘template<class T> decltype (g(x)) f(T)
[with T = int]’:
foo.cpp:22:6: required from here
foo.cpp:18:8: error: no matching function for call to ‘g(int&)’
foo.cpp:18:8: note: candidate is:
foo.cpp:15:8: note: template<class T> decltype (h(x)) g(T)
   auto g(T x) -> decltype(h(x)) { return h(x); }
        ^
foo.cpp:15:8: note: template argument deduction/substitution failed:
foo.cpp: In substitution of ‘template<class T> decltype (h(x)) g(T)
[with T = int]’:
foo.cpp:18:8: required by substitution of ‘template<class T>
decltype (g(x)) f(T) [with T = int]’
foo.cpp:22:6: required from here
foo.cpp:15:8: error: no matching function for call to ‘h(int&)’
foo.cpp:15:8: note: candidate is:
foo.cpp:12:8: note: template<class T> decltype (* x) h(T)
   auto h(T x) -> decltype(*x) { return *x; }
        ^
foo.cpp:12:8: note: template argument deduction/substitution failed:
foo.cpp: In substitution of ‘template<class T> decltype (* x) h(T)
[with T = int]’:
foo.cpp:15:8: required by substitution of ‘template<class T>
decltype (h(x)) g(T) [with T = int]’
foo.cpp:18:8: required by substitution of ‘template<class T>
decltype (g(x)) f(T) [with T = int]’
foo.cpp:22:6: required from here
foo.cpp:12:27: error: invalid type argument of unary ‘*’ (have ‘int’)
   auto h(T x) -> decltype(*x) { return *x; }

So GCC at least is documenting the root cause of the error. It would
still be nice to customize error reporting for certain classes of
failures in an API.