http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55722
Bug #: 55722 Summary: failed static_assert won't trigger a second time Classification: Unclassified Product: gcc Version: 4.8.0 Status: UNCONFIRMED Keywords: diagnostic Severity: normal Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: r...@gcc.gnu.org Created attachment 28986 --> http://gcc.gnu.org/bugzilla/attachment.cgi?id=28986 reduced testcase #include <type_traits> #include <utility> template<typename _Signature> struct _Bind_simple; template<typename _Callable, typename... _Args> struct _Bind_simple<_Callable(_Args...)> { template<typename _Callable2, typename... _Args2> explicit _Bind_simple(_Callable2&& __callable, _Args2&&... __args) { } }; template<typename _Func, typename... _BoundArgs> struct _Bind_simple_helper { typedef typename std::decay<_Func>::type __func_type; typedef _Bind_simple<__func_type(typename std::decay<_BoundArgs>::type...)> type; typedef std::result_of<__func_type(typename std::decay<_BoundArgs>::type...)> __result_of; }; template<typename _Callable> struct __assert_callable { static_assert(_Callable::value, "Invalid arguments for callable type"); }; template<typename _Func, typename... _Args> __assert_callable<std::false_type> __check_callable(...); template<typename _Func, typename... _Args, typename _Tp = _Bind_simple_helper<_Func, _Args...>, typename = typename _Tp::__result_of::type> typename _Tp::type __check_callable(int); template<typename _Callable, typename... _Args> decltype(__check_callable<_Callable, _Args...>(0)) __bind_simple(_Callable&& __callable, _Args&&... __args) { typedef _Bind_simple_helper<_Callable, _Args...> __helper_type; typedef typename __helper_type::type __bindexpr_type; return __bindexpr_type( std::forward<_Callable>(__callable), std::forward<_Args>(__args)...); } template<typename _Callable, typename... _Args> void call(_Callable&& __f, _Args&&... __args) { auto __bound_functor = __bind_simple(std::forward<_Callable>(__f), std::forward<_Args>(__args)...); } void f(int&); void test01() { call(f); #ifndef ONLY_ONE call(f, 1, 2); #endif } When compiled with ONLY_ONE defined this produces a nice "static assertion failed" message, as intended. $ g++ -std=c++11 -DONLY_ONE sa.cc: In instantiation of ‘struct __assert_callable<std::integral_constant<bool, false> >’: sa.cc:42:51: required by substitution of ‘template<class _Callable, class ... _Args> decltype (__check_callable<_Callable, _Args ...>(0)) __bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {}]’ sa.cc:55:39: required from ‘void call(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {}]’ sa.cc:62:9: required from here sa.cc:28:5: error: static assertion failed: Invalid arguments for callable type static_assert(_Callable::value, "Invalid arguments for callable type"); ^ But if ONLY_ONE is not defined, so there's a second invalid call(), the nice clear diagnostic turns into an unpleasant mess: $ g++ -std=c++11 sa.cc: In instantiation of ‘struct __assert_callable<std::integral_constant<bool, false> >’: sa.cc:42:51: required by substitution of ‘template<class _Callable, class ... _Args> decltype (__check_callable<_Callable, _Args ...>(0)) __bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {}]’ sa.cc:55:39: required from ‘void call(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {}]’ sa.cc:62:9: required from here sa.cc:28:5: error: static assertion failed: Invalid arguments for callable type static_assert(_Callable::value, "Invalid arguments for callable type"); ^ sa.cc: In instantiation of ‘decltype (__check_callable<_Callable, _Args ...>(0)) __bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int, int}; decltype (__check_callable<_Callable, _Args ...>(0)) = __assert_callable<std::integral_constant<bool, false> >]’: sa.cc:55:39: required from ‘void call(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int, int}]’ sa.cc:64:15: required from here sa.cc:47:96: error: could not convert ‘_Bind_simple<void (*(int, int))(int&)>((* & std::forward<void (&)(int&)>((* & __callable))), (* & std::forward<int>((* & __args#0))), (* & std::forward<int>((* & __args#1))))’ from ‘__bindexpr_type {aka _Bind_simple<void (*(int, int))(int&)>}’ to ‘__assert_callable<std::integral_constant<bool, false> >’ return __bindexpr_type( std::forward<_Callable>(__callable), std::forward<_Args>(__args)...); ^ sa.cc: In instantiation of ‘_Bind_simple<_Callable(_Args ...)>::_Bind_simple(_Callable2&&, _Args2&& ...) [with _Callable2 = void (&)(int&); _Args2 = {int, int}; _Callable = void (*)(int&); _Args = {int, int}]’: sa.cc:47:96: required from ‘decltype (__check_callable<_Callable, _Args ...>(0)) __bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int, int}; decltype (__check_callable<_Callable, _Args ...>(0)) = __assert_callable<std::integral_constant<bool, false> >]’ sa.cc:55:39: required from ‘void call(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int, int}]’ sa.cc:64:15: required from here sa.cc:12:7: warning: unused parameter ‘__callable’ [-Wunused-parameter] _Bind_simple(_Callable2&& __callable, _Args2&&... __args) ^ sa.cc:12:7: warning: unused parameter ‘__args#0’ [-Wunused-parameter] sa.cc:12:7: warning: unused parameter ‘__args#1’ [-Wunused-parameter] sa.cc: In function ‘decltype (__check_callable<_Callable, _Args ...>(0)) __bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int, int}; decltype (__check_callable<_Callable, _Args ...>(0)) = __assert_callable<std::integral_constant<bool, false> >]’: sa.cc:48:3: warning: control reaches end of non-void function [-Wreturn-type] } ^ Why doesn't the static_assertion happen for the second call? I'm trying to use this static assertion to simplify diagnostics for invalid std::thread initializations or std::call_once uses, but it only helps for the first such error.