//////////////////////////////////////////////////////////////////////////////// // sfinae_error.cpp // // Copyright 2012 Eric Niebler, Paul Fultz. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include // NOTE: this should do the noexcept dance, but I couldn't find a version that GCC would accept // when using this-> in member functions. #define RETURN(...) \ -> decltype(__VA_ARGS__) \ { \ return (__VA_ARGS__); \ } \ //////////////////////////////////////////////////////////////////////////////// // sfinae_error template struct sfinae_error; //////////////////////////////////////////////////////////////////////////////////////// // find_first_sfinae_error template struct find_first_sfinae_error {}; template struct find_first_sfinae_error : find_first_sfinae_error {}; template struct find_first_sfinae_error, Tail...> { typedef sfinae_error type; }; struct sfinae_error_base { // Should only be found via ADL when one of the argument is a sfinae_error template friend typename find_first_sfinae_error::type try_find_sfinae_error(int, Args &&...args) noexcept { return typename find_first_sfinae_error::type(); } }; template struct sfinae_error : sfinae_error_base { virtual void what() const noexcept { typedef decltype(std::declval()(std::declval()...)) error_message; } }; template inline int try_find_sfinae_error(long, Args &&...) noexcept { return 0; } //////////////////////////////////////////////////////////////////////////////////////// // Many thanks to Paul Fultz for some of the ideas behind try_call template struct try_call_wrapper { Fun fun_; template auto call_or_fail_(int, Args &&... args) const RETURN( fun_(static_cast(args)...) ) template sfinae_error call_or_fail_(sfinae_error, Args &&... args) const noexcept { return sfinae_error(); } try_call_wrapper() = default; try_call_wrapper(try_call_wrapper const &) = default; try_call_wrapper(try_call_wrapper &&) = default; try_call_wrapper &operator=(try_call_wrapper const &) = default; try_call_wrapper &operator=(try_call_wrapper &&) = default; explicit constexpr try_call_wrapper(Fun &&fun) noexcept(noexcept(Fun(static_cast(fun)))) : fun_(static_cast(fun)) {} template auto operator()(Args &&...args) const RETURN( this->call_or_fail_( // Must be an unqualified call to possibly find the sfinae_error friend function try_find_sfinae_error(1, static_cast(args)...) , static_cast(args)... ) ) template sfinae_error operator()(Args &&...args) const volatile noexcept { // Uncomment this line to get the full template instantiation backtrace //const_cast(this)->fun_(static_cast(args)...); return sfinae_error(); } }; template inline constexpr auto try_call(Fun &&fun) RETURN( try_call_wrapper(static_cast(fun)) ) struct S0 { template auto operator()(T t) const RETURN( t + 1 ) }; struct S1 { template auto operator()(T t) const RETURN( try_call(S0())(try_call(S0())(t)) ) }; struct S2 { template auto operator()(T t) const RETURN( try_call(S1())(t) ) }; struct foo {}; int main() { int i = S2()(32); auto x = S2()(foo()); }