c++ - Detect idiom with function failing static_assert -
is there way use detection idiom (or method) test whether function valid given template arguments, if fails due static_assert?
the example below illustrates validity of foo (failing return type computation) detected intended, of bar (failing static_assert) not.
#include <iostream> #include <type_traits> template <typename... t> using void_t = void; template <class alwaysvoid, template<class...> class op, class... args> struct detector: std::false_type { }; template <template<class...> class op, class... args> struct detector<void_t<op<args...>>, op, args...>: std::true_type { }; template <template<class...> class op, class... args> constexpr bool is_detected = detector<void, op, args...>::value; template <typename t> std::enable_if_t<!std::is_void<t>::value> foo() { std::cout << "foo" << std::endl; } template <typename t> void bar() { static_assert( !std::is_void<t>::value ); std::cout << "bar" << std::endl; } template <typename t> using foo_t = decltype(foo<t>()); template <typename t> using bar_t = decltype(bar<t>()); int main(int argc, char* argv[]) { foo<int>(); // foo<void>(); // fails expected bar<int>(); // bar<void>(); // fails expected std::cout << std::boolalpha; // detection works foo std::cout << is_detected<foo_t,int > << std::endl; // true std::cout << is_detected<foo_t,void> << std::endl; // false // not bar std::cout << is_detected<bar_t,int > << std::endl; // true std::cout << is_detected<bar_t,void> << std::endl; // true !!! } this reason can't detect if boost::lexical_cast valid given types.
it's not possible use sfinae proper output here, because sfinae rules operate on declarations, not definitions.
the type of bar declared void(void), declaration okay far sfinae concerned.
if write real detection idiom (like i did here), , use so:
template <typename t> using cancallfoo_t = decltype(&foo<t>); template<class t> using cancallfoo = detect<t, cancallfoo_t, void>; template<class t> using cancallbar_t = decltype(&bar<t>); template< class t> using cancallbar = detect<t, cancallbar_t, void>; //... std::cout << cancallfoo<int>::value << std::endl; // true std::cout << cancallfoo<void>::value << std::endl; // false std::cout << cancallbar<int>::value << std::endl; std::cout << cancallbar<void>::value << std::endl; you'll notice sfinae succeeds , compiler error when definition parsed.
error: static assertion failed
static_assert( !std::is_void<t>::value );
notice works foo because foo's declared type fail sfinae void
the point of static_assert make compilation fail if no other better match found, not substitution sfinae.
wiki
Comments
Post a Comment