在c++中检测运算符是否存在和可调用(考虑static_asserts)
Detect whether operator exists and callable in c++ (considering static_asserts)
给定 2 种类型 T
和 U
我想检测是否可以在对象之间调用 operator *
(即是否可以写 t * u
在哪里t
是 T
类型,u
是 U
)
类型
我正在使用 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;
但现在我有 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_asserts 有更好的错误消息)。
So, my question is, how to fix my code to not detect methods when they static_asserted out?
你根本做不到。这只是 static_assert
的缺点之一——无法从外部验证操作的有效性。那是因为 static_assert
没有发生在 operator*
实例化的 "immediate context" 中,所以 SFINAE 不适用——它总是一个硬错误。
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).
我很同情。但这基本上是一种权衡。 SFINAE 和类型检查,或 static_assert
和更清晰的错误。 (当然在这种情况下你可以只写一个非模板 A<bool> operator*(A<bool> const&, A<bool> const&)
但这可能不是重点)。
给定 2 种类型 T
和 U
我想检测是否可以在对象之间调用 operator *
(即是否可以写 t * u
在哪里t
是 T
类型,u
是 U
)
我正在使用 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;
但现在我有 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_asserts 有更好的错误消息)。
So, my question is, how to fix my code to not detect methods when they static_asserted out?
你根本做不到。这只是 static_assert
的缺点之一——无法从外部验证操作的有效性。那是因为 static_assert
没有发生在 operator*
实例化的 "immediate context" 中,所以 SFINAE 不适用——它总是一个硬错误。
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).
我很同情。但这基本上是一种权衡。 SFINAE 和类型检查,或 static_assert
和更清晰的错误。 (当然在这种情况下你可以只写一个非模板 A<bool> operator*(A<bool> const&, A<bool> const&)
但这可能不是重点)。