Boost logo

Boost :

Subject: Re: [boost] C++11 challenge: ASSERT_INVALID_EXPR
From: Jeremiah Willcock (jewillco_at_[hidden])
Date: 2011-12-04 12:20:19


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;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk