#include <utility>

template <class T>
constexpr bool always_true(T&&) { return true; }

template<bool>
struct always_bool { using type = bool; };

template <class T, class U>
constexpr bool true_if_constexpr(T, U) { return false; }

template <class U>
constexpr auto true_if_constexpr(int, U)
  -> typename always_bool
     < ::always_true(decltype(std::declval<U>()()){}.member) >::type
{
	return true;
}

struct empty {};

#define IS_CONSTEXPR(decl, expr)                                               \
(::true_if_constexpr(0,                                                        \
 []                                                                            \
 {                                                                             \
	TYPE(decl) NAME(decl);                                                     \
                                                                               \
	struct return_type                                                         \
	{                                                                          \
		decltype(expr)&& member = static_cast<decltype(expr)&&>(expr);         \
	};                                                                         \
                                                                               \
	return return_type{};                                                      \
 })                                                                            \
)


#define IS_INVALID_EXPR(decl, expr) (!IS_VALID_EXPR(decl,expr))
 
#define FIRST_ARG_EXPANDED_(a,b) FORWARD a
#define FIRST_ARG_EXPANDED(...) FIRST_ARG_EXPANDED_(__VA_ARGS__)
 
#define SECOND_ARG_EXPANDED_(a,b) b
#define SECOND_ARG_EXPANDED(...) SECOND_ARG_EXPANDED_(__VA_ARGS__)
 
#define PARENTHESIZED_PART_(...) (__VA_ARGS__),
#define TYPE(arg) FIRST_ARG_EXPANDED( PARENTHESIZED_PART_ arg )
 
#define NAME(arg) SECOND_ARG_EXPANDED( PARENTHESIZED_PART_ arg )
 
#define STRINGIZE_(...) #__VA_ARGS__
#define STRINGIZE(...) STRINGIZE_(__VA_ARGS__)

#define FORWARD(...) __VA_ARGS__

template<class T>
bool foo(T&&) { return true; }

template<class T>
constexpr bool constexpr_foo(T&&) { return true; }

#define STATIC_ASSERT_CONSTEXPR_(n, f, s, decl, expr)                          \
(n IS_CONSTEXPR(decl, expr),                                                   \
"\n\n********************\n\n"                                                 \
"Given:\n    " STRINGIZE(TYPE(decl)) " " STRINGIZE(NAME(decl)) ";\n\n"         \
"The following expression was expected to" f " be constexpr but was" s ":\n"   \
"    " STRINGIZE(expr) "\n\n********************")
 
#define STATIC_ASSERT_CONSTEXPR(decl, expr)                                    \
static_assert                                                                  \
STATIC_ASSERT_CONSTEXPR_(, , " not", decl, expr)
 
#define STATIC_ASSERT_NOT_CONSTEXPR(decl, expr)                                \
static_assert                                                                  \
STATIC_ASSERT_CONSTEXPR_(!, " not", , decl, expr)

STATIC_ASSERT_CONSTEXPR
(
	(constexpr int) var = 5,
	constexpr_foo(var)
);


STATIC_ASSERT_NOT_CONSTEXPR
(
	(constexpr int) var = 5,
	foo(var)
);

int main() {}
