检查两种类型是否具有可比性
Checking whether or not 2 types are comparable
我有以下代码来确定 2 种类型是否具有可比性。
template<typename T, typename U, typename = std::void_t<>>
struct is_comparable
: std::false_type
{};
template<typename T, typename U>
struct is_comparable<T, U, std::void_t<decltype((std::declval<T>() == std::declval<U>()))>>
: std::true_type
{};
这是一种可以接受的方式来实现我想要做的事情吗?你能看出这个设计有什么问题吗?
编辑
牢记 cdhowie 的评论和 Henri Menki 的回答,这就是代码现在的样子。
namespace meta
{
template<typename T, typename U, typename = std::void_t<>>
struct has_equal_to_operator
: std::false_type
{};
template<typename R, typename T, typename U, typename = std::void_t<>>
struct has_equal_to_operator_r
: std::false_type
{};
template<typename T, typename U, typename = std::void_t<>>
struct has_nothrow_equal_to_operator
: std::false_type
{};
template<typename R, typename T, typename U, typename = std::void_t<>>
struct has_nothrow_equal_to_operator_r
: std::false_type
{};
template<typename T, typename U>
struct has_equal_to_operator<T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::true_type
{};
template<typename R, typename T, typename U>
struct has_equal_to_operator_r<R, T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::is_convertible<decltype(std::declval<T>() == std::declval<U>()), R>
{};
template<typename T, typename U>
struct has_nothrow_equal_to_operator<T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::bool_constant<noexcept(std::declval<T>() == std::declval<U>())>
{};
template<typename R, typename T, typename U>
struct has_nothrow_equal_to_operator_r<R, T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::bool_constant<(noexcept(std::declval<T>() == std::declval<U>()) && std::is_convertible_v<decltype(std::declval<T>() == std::declval<U>()), R>)>
{};
template<typename T, typename U>
inline constexpr auto has_equal_to_operator_v = has_equal_to_operator<T, U>::value;
template<typename R, typename T, typename U>
inline constexpr auto has_equal_to_operator_r_v = has_equal_to_operator_r<R, T, U>::value;
template<typename T, typename U>
inline constexpr auto has_nothrow_equal_to_operator_v = has_nothrow_equal_to_operator<T, U>::value;
template<typename R, typename T, typename U>
inline constexpr auto has_nothrow_equal_to_operator_r_v = has_nothrow_equal_to_operator_r<R, T, U>::value;
}
你不远了,但你不需要C++17:C++11就够了
#include <type_traits>
#include <iostream>
template <typename T, typename U, typename = void>
struct is_comparable : std::false_type
{};
template <typename T, typename U>
struct is_comparable<T, U,
decltype((std::declval<T>() == std::declval<U>()), void())>
: std::true_type
{};
struct X
{ };
int main()
{
static_assert(false == is_comparable<X, X>(), "!");
static_assert( true == is_comparable<std::string, std::string>(), "!!");
static_assert(false == is_comparable<int, std::string>(), "!!!");
static_assert( true == is_comparable<int, int>(), "!!!!");
}
这是问题中带有 void_t
的解决方案。此外,我会检查比较是否产生正确的类型(在这种情况下为bool
)。
#include <type_traits>
#include <iostream>
template < typename T, typename U >
using equality_comparison_t = decltype(std::declval<T&>() == std::declval<U&>());
template < typename T, typename U, typename = std::void_t<> >
struct is_equality_comparable
: std::false_type
{};
template < typename T, typename U >
struct is_equality_comparable < T, U, std::void_t< equality_comparison_t<T,U> > >
: std::is_same< equality_comparison_t<T,U>, bool >
{};
struct X {};
struct Y { int operator==(Y const&) { return 1; } };
int main()
{
static_assert(false == is_equality_comparable<X, X>(), "!");
static_assert( true == is_equality_comparable<std::string, std::string>(), "!!");
static_assert(false == is_equality_comparable<int, std::string>(), "!!!");
static_assert( true == is_equality_comparable<int, int>(), "!!!!");
static_assert(false == is_equality_comparable<Y, Y>(), "!!!!!");
}
我有以下代码来确定 2 种类型是否具有可比性。
template<typename T, typename U, typename = std::void_t<>>
struct is_comparable
: std::false_type
{};
template<typename T, typename U>
struct is_comparable<T, U, std::void_t<decltype((std::declval<T>() == std::declval<U>()))>>
: std::true_type
{};
这是一种可以接受的方式来实现我想要做的事情吗?你能看出这个设计有什么问题吗?
编辑
牢记 cdhowie 的评论和 Henri Menki 的回答,这就是代码现在的样子。
namespace meta
{
template<typename T, typename U, typename = std::void_t<>>
struct has_equal_to_operator
: std::false_type
{};
template<typename R, typename T, typename U, typename = std::void_t<>>
struct has_equal_to_operator_r
: std::false_type
{};
template<typename T, typename U, typename = std::void_t<>>
struct has_nothrow_equal_to_operator
: std::false_type
{};
template<typename R, typename T, typename U, typename = std::void_t<>>
struct has_nothrow_equal_to_operator_r
: std::false_type
{};
template<typename T, typename U>
struct has_equal_to_operator<T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::true_type
{};
template<typename R, typename T, typename U>
struct has_equal_to_operator_r<R, T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::is_convertible<decltype(std::declval<T>() == std::declval<U>()), R>
{};
template<typename T, typename U>
struct has_nothrow_equal_to_operator<T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::bool_constant<noexcept(std::declval<T>() == std::declval<U>())>
{};
template<typename R, typename T, typename U>
struct has_nothrow_equal_to_operator_r<R, T, U, std::void_t<decltype(std::declval<T>() == std::declval<U>())>>
: std::bool_constant<(noexcept(std::declval<T>() == std::declval<U>()) && std::is_convertible_v<decltype(std::declval<T>() == std::declval<U>()), R>)>
{};
template<typename T, typename U>
inline constexpr auto has_equal_to_operator_v = has_equal_to_operator<T, U>::value;
template<typename R, typename T, typename U>
inline constexpr auto has_equal_to_operator_r_v = has_equal_to_operator_r<R, T, U>::value;
template<typename T, typename U>
inline constexpr auto has_nothrow_equal_to_operator_v = has_nothrow_equal_to_operator<T, U>::value;
template<typename R, typename T, typename U>
inline constexpr auto has_nothrow_equal_to_operator_r_v = has_nothrow_equal_to_operator_r<R, T, U>::value;
}
你不远了,但你不需要C++17:C++11就够了
#include <type_traits>
#include <iostream>
template <typename T, typename U, typename = void>
struct is_comparable : std::false_type
{};
template <typename T, typename U>
struct is_comparable<T, U,
decltype((std::declval<T>() == std::declval<U>()), void())>
: std::true_type
{};
struct X
{ };
int main()
{
static_assert(false == is_comparable<X, X>(), "!");
static_assert( true == is_comparable<std::string, std::string>(), "!!");
static_assert(false == is_comparable<int, std::string>(), "!!!");
static_assert( true == is_comparable<int, int>(), "!!!!");
}
这是问题中带有 void_t
的解决方案。此外,我会检查比较是否产生正确的类型(在这种情况下为bool
)。
#include <type_traits>
#include <iostream>
template < typename T, typename U >
using equality_comparison_t = decltype(std::declval<T&>() == std::declval<U&>());
template < typename T, typename U, typename = std::void_t<> >
struct is_equality_comparable
: std::false_type
{};
template < typename T, typename U >
struct is_equality_comparable < T, U, std::void_t< equality_comparison_t<T,U> > >
: std::is_same< equality_comparison_t<T,U>, bool >
{};
struct X {};
struct Y { int operator==(Y const&) { return 1; } };
int main()
{
static_assert(false == is_equality_comparable<X, X>(), "!");
static_assert( true == is_equality_comparable<std::string, std::string>(), "!!");
static_assert(false == is_equality_comparable<int, std::string>(), "!!!");
static_assert( true == is_equality_comparable<int, int>(), "!!!!");
static_assert(false == is_equality_comparable<Y, Y>(), "!!!!!");
}