|
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