
On Fri, 6 Jul 2012, Eric Niebler wrote:
I'm running into a usability problem with the extended SFINAE rules that could effect best practice for all new C++ libraries. I'm hoping some clever person in the Boost community can help me.
I find that in highly generic code, using decltype to define the return type of functions is very handy. Dave A. suggested a RETURNS macro to simplify this idiom:
<https://groups.google.com/d/msg/boost-devel-archive/OzJ5Ft3pSnU/b_Ter9bgNqAJ>
It's used like this:
template<typename T> auto foo( T && t ) RETURNS( some-expression-using-t );
This is great and I use it a lot. Now, imagine you have a library of such functions calling other such functions: function A calls B calls ... calls Y, calls Z, all of which use decltype to declare their return types. Now, the user calls A passing a variable t for which the expression in Z's return type calculation makes no sense. Extended SFINAE kicks in, and Z simply disappears. Since Z has disappeared, the expression in Y's return type makes no sense, so Y disappears, too. And so on up the chain.
The end result is that the user is presented with an error like: "no viable function A, template substitution failed." The user is given no information about which function in the chain failed to compile, or why. This is a serious usability problem!
... in your compiler.
All suggestions welcome,
Use g++. template<class T> auto h(T x)->decltype(x.smurf()){return x.smurf();} template<class T> auto g(T x)->decltype(h(x)){return h(x);} template<class T> auto f(T x)->decltype(g(x)){return g(x);} int main(){ f(3); } e.cc: In function 'int main()': e.cc:5:6: error: no matching function for call to 'f(int)' f(3); ^ e.cc:5:6: note: candidate is: e.cc:3:24: note: template<class T> decltype (g(x)) f(T) template<class T> auto f(T x)->decltype(g(x)){return g(x);} ^ e.cc:3:24: note: template argument deduction/substitution failed: e.cc: In substitution of 'template<class T> decltype (g(x)) f(T) [with T = int]': e.cc:5:6: required from here e.cc:3:24: error: no matching function for call to 'g(int&)' e.cc:3:24: note: candidate is: e.cc:2:24: note: template<class T> decltype (h(x)) g(T) template<class T> auto g(T x)->decltype(h(x)){return h(x);} ^ e.cc:2:24: note: template argument deduction/substitution failed: e.cc: In substitution of 'template<class T> decltype (h(x)) g(T) [with T = int]': e.cc:3:24: required by substitution of 'template<class T> decltype (g(x)) f(T) [with T = int]' e.cc:5:6: required from here e.cc:2:24: error: no matching function for call to 'h(int&)' e.cc:2:24: note: candidate is: e.cc:1:24: note: template<class T> decltype (x.smurf()) h(T) template<class T> auto h(T x)->decltype(x.smurf()){return x.smurf();} ^ e.cc:1:24: note: template argument deduction/substitution failed: e.cc: In substitution of 'template<class T> decltype (x.smurf()) h(T) [with T = int]': e.cc:2:24: required by substitution of 'template<class T> decltype (h(x)) g(T) [with T = int]' e.cc:3:24: required by substitution of 'template<class T> decltype (g(x)) f(T) [with T = int]' e.cc:5:6: required from here e.cc:1:24: error: request for member 'smurf' in 'x', which is of non-class type 'int' -- Marc Glisse