Given 2 types T
and U
I want to detect whether it's possible to call operator *
between those to objects (i.e is it possible to write t * u
where t
is of type T
and u
is of type U
)
I'm using c++ detection idiom but since it's not yet available in my compiler I implemented it myself like this
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...>;
};
} // namespace detail
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
template< template<class...> class Op, class... Args >
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
Now I have such helper:
template <typename T, typename U>
using multiply = decltype(std::declval<T>() * std::declval<U>());
and to detect whether it's callable I call
bool can_multiply = is_detected_v<multiply, T, U>
It's almost fine , for example this 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 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>
can't be multiplied by A<bool>
but my code detects that it's possible
std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1
A<bool>() * A<bool>(); // does't compile
So, my question is, how to fix my code to not detect methods when they 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).
So, my question is, how to fix my code to not detect methods when they static_asserted out?
You simply can't. That's just one of the downsides of static_assert
- there is no way to externally verify the validity of an operation. That's because static_assert
doesn't happen in the "immediate context" of the instantiation of operator*
, and so SFINAE doesn't apply - it will always be a hard error.
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).
I sympathize. But that's basically the trade-off. SFINAE and type checking, or static_assert
and clearer errors. (Of course in this case you could just write a non-template A<bool> operator*(A<bool> const&, A<bool> const&)
but that's probably besides the point).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With