检测操作符是否存在并可在c++中调用(考虑static_assertions)

Detect whether operator exists and callable in c++ (considering static_asserts)

本文关键字:考虑 调用 static assertions c++ 是否 操作符 存在 检测      更新时间:2023-10-16

给定2种类型TU,我想检测是否可以在这些对象之间调用operator *(即是否可以编写t * u,其中tT类型,uU类型)

我正在使用c++检测习惯用法,但由于它在我的编译器中还不可用,所以我自己实现了它,像这样

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;

现在我有了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>();
}

这里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 ?我想我可以用一些sfinae取代static_assert,但我不想(因为我没有访问权限,除了static_断言有更好的错误消息)。

所以,我的问题是,如何修复我的代码不检测方法时,他们static_asserted ?

你就是不能。这只是static_assert的缺点之一——没有办法从外部验证操作的有效性。这是因为static_assert不会发生在operator*实例化的"即时上下文中",因此SFINAE不适用-它将始终是一个硬错误。

我想我可以用一些sfinae代替static_assert,但我不想这样做(因为我没有访问权限,而且static_assert有更好的错误消息)。

我同情。但这基本上是一种权衡。SFINAE和类型检查,或static_assert和更清晰的错误。(当然,在这种情况下,您可以只编写一个非模板A<bool> operator*(A<bool> const&, A<bool> const&),但这可能不是重点)。