检查2种类型是否具有可比性

时间:2017-06-13 20:35:06

标签: c++ templates c++17 typetraits

我有以下代码来确定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;
}

2 个答案:

答案 0 :(得分:2)

以下是问题中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>(), "!!!!!");
}

答案 1 :(得分: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>(), "!!!!");
 }