2017-06-13 69 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

相關問題