2017-06-13 16 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 
{}; 

これは、私がしようとしていることを達成するための許容可能な方法ですか?あなたはこのデザインの問題を見ることができますか?

EDIT

cdhowieさんのコメントと心の中でアンリ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; 
} 
+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

@ヤマハリいいえ、実際はありません。私はそれが違いをもたらすとは思わない。 –

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

ちょうど 'f()'の代わりに 'true == f()'と書くのはなぜでしょうか? – Barry

+1

@Barry - aestethicalな理由:私は "好きではありません!演算子(それは小さすぎる:私はそれを参照してください!)ので、私は真偽値をチェックするときにコードを書くとき、私は明示的にそれを参照してください。私は知っている...それは超過です。しかし、私はそれがより明確でシンプルであることがわかります。 – max66

関連する問題