2017-06-13 97 views
2

我有以下代码来确定2种类型是否具有可比性。检查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的评论和亨利面机的记答案,这是现在的代码的外观。

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; 
} 
+1

我澄清'is_equality_comparable'因为还有其他种类的比较(不平等,关系...)。 – cdhowie

回答

1

这里是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>(), "!!!!!"); 
} 
+0

是否有一个特定的原因将'std :: declval ()'更改为'std :: declval ()'? – Yamahari

+0

@Yamahari不,实际上不是。我不认为这有什么不同。 –

0

你并不远,但你并不需要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>(), "!!!!"); 
} 
+0

我在我的代码的其余部分使用C++ 17,所以也可以在这里使用它:)还是谢谢! – Yamahari

+1

你为什么要写'true == f()',而不仅仅是......'f()' – Barry

+1

@Barry - 一个美学原因:我不喜欢“!”运算符(它太小了:我不'看到它!)所以,当我在编写代码时检查真值和假值时,我就明确了它。我知道......它很超级。但我觉得它更加清晰和简单。 – max66

相关问题