
I spent some time playing with this today. Attached is my best shot. The basic idea is to change the RETURNS macro to -- in addition to declaring the trailing return type and the function body -- also define an implicit conversion to a function pointer. That gets selected as the function called in the case that sfinae fails. That function returns a sfinae_error that contains some useful information: the text of the expression that failed to compile, the file and line number of the sfinae failure, and the types of the function parameters (mangled, unfortunately).
Unfortunately, this results in a run-time error instead of compile-time.
Can anybody do better?
Attached is code that does present a compile-time error. It uses a function adaptor called `sfinae_error`. This will force sfinae success on the expression type dedcution by using a fail-through type. The fail through type doesn't matter since we know the function call will produce a compile error either way. So now, the `S0` class can be defined like this: struct S0_sfinae { template<typename T> auto operator()(T t) const RETURN( t + 1 ) }; typedef sfinae_error<S0_sfinae> S0; Then when you try to call it like this: struct foo {}; S2()(foo()); Clang will output the error inside of `sfinae_error` function adaptor with a full backtrace. At the bottom it will say: note: candidate template ignored: substitution failure [with T = foo]: invalid operands to binary expression ('foo' and 'int') auto operator()(T t) const RETURN( t + 1 ) Which is what you want. Futhermore, this can be used even when there are multiple overloads in the `S0` class.