
On Sun, 4 Dec 2011, Dave Abrahams wrote:
I don't know whether this is actually possible, but I was thinking today that there might be a way to use the new SFINAE to detect errors in a large class of invalid expressions without actually causing a hard error, and thereby build an assertion that fails compilation when passed a valid expression and passes for any invalid expression in the large class mentioned above.
Any takers?
Here's the best I've been able to come up with. It works on GCC 4.6 (I tested with a prerelease, so the bug I mention might have been fixed). It only works within classes, and you need to use a separate template parameter in the tested expression (it would be nice if you could shadow template parameters in a nested class, BTW). -- Jeremiah Willcock #include <utility> #include <boost/preprocessor/cat.hpp> #include <boost/mpl/bool.hpp> template <typename T> struct identity {typedef T type;}; template <typename U> struct test_template { #define BOOST_ASSERT_INVALID_EXPR(tparam, e, msg) \ struct BOOST_PP_CAT(invalid_expr_test, __LINE__) { \ template <typename BOOST_PP_CAT(tparam, _), typename = decltype((e))> struct expr_type {typedef void type;}; \ static boost::mpl::bool_<false> is_ok(bool); \ template <typename T> static boost::mpl::bool_<true> is_ok(T*, const typename expr_type<T>::type* = 0); \ }; \ /* identity here works around parsing bug in GCC 4.6 (decltype(foo)::value doesn't work) */ \ static_assert(identity<decltype(BOOST_PP_CAT(invalid_expr_test, __LINE__)::is_ok((tparam*)0))>::type::value, msg); BOOST_ASSERT_INVALID_EXPR(U, std::declval<U_>() + "bar", "valid"); }; #if 0 // This requires the ability to put member templates in local classes template <typename T> void test2(T*) { BOOST_ASSERT_INVALID_EXPR(T, "foo" + std::declval<T_>(), "valid2"); } #endif int main(int, char**) { test_template<int> a; test_template<char*> b; #if 0 test2((int*)0); test2((char**)0); #endif return 0; }