Given 2 types of T and U , I want to determine if operator * can be called between these objects (i.e., you can write t * u , where T is of type T and U is of type U )
I use the C ++ discovery identifier , but since it is not yet available in my compiler, I myself implemented this as
struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(nonesuch const&) = delete; void operator=(nonesuch const&) = delete; }; namespace detail { template <class Default, class AlwaysVoid, template<class...> class Op, class... Args> struct detector { using value_t = std::false_type; using type = Default; }; template <class Default, template<class...> class Op, class... Args> struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> { using value_t = std::true_type; using type = Op<Args...>; }; }
Now I have a helper like this:
template <typename T, typename U> using multiply = decltype(std::declval<T>() * std::declval<U>());
and determine if it is callable, I call
bool can_multiply = is_detected_v<multiply, T, U>
This is almost excellent, for example, it prints 1, 0, as expected
std::cout << is_detected_v<multiply, int, int> << std::endl; std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl;
But now I have a class
template<typename T> class A { }; template<typename T> A<T> operator*(const A<T>&, const A<T>&) { static_assert(!std::is_same<bool, T>::value); return A<T>(); }
here A<bool> cannot be multiplied by A<bool> , but my code detects what is possible
std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl;
So my question is how to fix my code so that it does not detect methods when they are static_asserted out? I suppose I can replace static_assert with some sfinae, but I don't want to (because I don't have access, and besides, static_asserts have better error messages).