/////////////////////////////////////////////////////////////////////////////// // Copyright 2012 Eric Niebler. 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) #define BOOST_PP_VARIADICS #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef std::pair binding_t; class sfinae_error { char const *expr_; char const *filename_; int line_; std::vector bindings_; public: sfinae_error(char const *expr, char const *filename, int line, std::initializer_list bindings) : expr_(expr) , filename_(filename) , line_(line) , bindings_(bindings) {} std::string what() const { std::stringstream str; str << "ERROR: sfinae failed for expression '" << expr_ << "' " << "in file '"<< filename_ << "' on line " << line_; if(!bindings_.empty()) { str << " with <"; bool first = true; for(auto const &binding : bindings_) { str << (first?"":", ") << "'" << binding.first << "'" << " of type '" << binding.second.name() << "'"; first = false; } str << '>'; } return str.str(); } }; class any { std::type_info const &ti_; public: template any(T &&) : ti_(typeid(T)) {} std::type_info const & type() const { return ti_; } }; #define BOOST_SFINAE_ERROR_FUN(Z, N, D)\ typedef sfinae_error (*BOOST_PP_CAT(sfinae_error_fun_, N))(BOOST_PP_ENUM_PARAMS_Z(Z, N, any a)); #define BOOST_SFINAE_ERROR_LIMIT_ARITY 50 BOOST_PP_REPEAT(BOOST_SFINAE_ERROR_LIMIT_ARITY, BOOST_SFINAE_ERROR_FUN, ~) #define BOOST_SFINAE_ERROR_VARIABLE_BINDING(Z, N, D) \ {BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(N, D)), BOOST_PP_CAT(a, N).type()} \ /**/ #define RETURN(SIG, ...) \ -> decltype(__VA_ARGS__) { return __VA_ARGS__; } \ \ operator BOOST_PP_CAT(sfinae_error_fun_, BOOST_PP_VARIADIC_SIZE SIG)() const \ { \ return [](BOOST_PP_ENUM_PARAMS(BOOST_PP_VARIADIC_SIZE SIG, any a)) \ { \ return sfinae_error( \ #__VA_ARGS__ \ , __FILE__ \ , __LINE__ \ , {BOOST_PP_ENUM(BOOST_PP_VARIADIC_SIZE SIG, BOOST_SFINAE_ERROR_VARIABLE_BINDING, SIG)}\ ); \ }; \ } \ /**/ struct S0 { template auto operator()(T t) const RETURN( (t), t + 1 ) }; struct S1 { template auto operator()(T t) const RETURN( (t), S0()(t) ) }; struct S2 { template auto operator()(T t) const RETURN( (t), S1()(t) ) }; struct XXX {}; int main() { int i = S2()(42); std::cout << "Should be 43 : " << i << std::endl; XXX xxx; sfinae_error err = S2()(xxx); std::cout << err.what() << std::endl; }