Учитывая 2 типа T
и U
Я хочу, чтобы обнаружить, можно ли назвать operator *
между теми объектами (т.е. есть возможность написать t * u
где t
имеет типа T
и u
имеет тип U
)Detect существует ли оператор и вызываемые в C++ (с учетом static_asserts)
Я использую c++ detection idiom, но так как он еще не доступен в моем компиляторе я реализовал это сам, как этот
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;
Сейчас я есть такой помощник:
template <typename T, typename U>
using multiply = decltype(std::declval<T>() * std::declval<U>());
и обнаружить, является ли это вызываемая я называю
bool can_multiply = is_detected_v<multiply, T, U>
Это почти нормально, например, это печатает 1, 0, как и ожидалось
std::cout << is_detected_v<multiply, int, int> << std::endl;
std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl;
Но теперь у меня есть класс
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>();
}
he повторно A<bool>
не может быть умножена на A<bool>
, но мой код определяет, что это возможно
std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1
A<bool>() * A<bool>(); // does't compile
Итак, мой вопрос, как исправить мой код, чтобы не обнаружить методы, когда они static_asserted вне дома? Я полагаю, что я могу заменить static_assert
на некоторые sfinae, но я не хочу (потому что у меня нет доступа, и, кроме того, static_asserts имеют лучшие сообщения об ошибках).
Объясняя, почему может помочь (SFINAE проверка должна быть сделана во время разрешения перегрузки, заставляя каждый компилятор компилировать все функции и определить, есть ли у него какой-либо незаконный код до определения, которые перегружают назвать бы как трудно для компиляторов, и может привести к в удивительном поведении (я предпочел 'void *' over 'T *', потому что ваш код 'T * 'содержит ошибку, приводящую к ошибке в уровнях 2-го уровня, вложенных вглубь). Проверка SFINAE является компромиссом, и даже там MSVC падает на них * hard *. – Yakk