【问题标题】:Check if class/struct has a specific operator [duplicate]检查类/结构是否具有特定的运算符 [重复]
【发布时间】:2017-01-13 16:32:37
【问题描述】:

我需要专门化我的一个模板,并希望根据可用的运算符来做。

我基本上需要知道我是否可以做到Foo == Bar

template<class T >
std::enable_if_t<has_equalOperator<T>::value> Compare( const T& other )
{
  // can compare using ==
  ...
} 

template<class T >
std::enable_if_t<!has_equalOperator<T>::value> Compare( const T& other )
{
  // cannot compare use some other method
  ...
} 

标准是否有类似的东西?如果没有,我该如何实施?

【问题讨论】:

标签: c++ c++11 operator-overloading


【解决方案1】:

在C++17中,可以用std::is_detected简化:

typename <typename LHS, typename RHS>
using equal_t = decltype(std::declval<LHS>() == std::declval<RHS>());

template <typename T>
using has_equal = std::is_detected<equal_t, T, T>;

Demo

【讨论】:

    【解决方案2】:

    这种特质类型几乎总是采用以下形式:

    #include <utility>
    #include <iostream>
    #include <string>
    
    template<class T, class Arg>
      struct has_equals_impl
      {
        template<class U> static 
          auto test(const U* p) 
          -> decltype( /* the test is here */
                      (*p) == std::declval<Arg>(), 
                       /* end of test */
                      void(), std::true_type());
    
        static auto test(...) -> std::false_type;
    
        using type = decltype(test((const T*)nullptr));
    
      };
    
    // this typedef ensures that the actual type is either std::true_type or std::false_type
    template<class T, class Arg> using has_equals = typename has_equals_impl<T, Arg>::type;
    
    int main()
    {
      // int == int? yes
      std::cout << has_equals<int, int>() << std::endl;
    
      // string == int? no
      std::cout << has_equals<std::string, int>() << std::endl;
    }
    

    这是一套几乎完整的二元运算符检查器,带有一些测试。

    您应该大致了解一下。请注意,我必须创建 left_shiftright_shift 函数对象,因为标准库中不存在这些对象。

    #include <utility>
    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <cassert>
    
    
    template<class X, class Y, class Op>
    struct op_valid_impl
    {
        template<class U, class L, class R>
        static auto test(int) -> decltype(std::declval<U>()(std::declval<L>(), std::declval<R>()),
                                          void(), std::true_type());
    
        template<class U, class L, class R>
        static auto test(...) -> std::false_type;
    
        using type = decltype(test<Op, X, Y>(0));
    
    };
    
    template<class X, class Y, class Op> using op_valid = typename op_valid_impl<X, Y, Op>::type;
    
    namespace notstd {
    
        struct left_shift {
    
            template <class L, class R>
            constexpr auto operator()(L&& l, R&& r) const
            noexcept(noexcept(std::forward<L>(l) << std::forward<R>(r)))
            -> decltype(std::forward<L>(l) << std::forward<R>(r))
            {
                return std::forward<L>(l) << std::forward<R>(r);
            }
        };
    
        struct right_shift {
    
            template <class L, class R>
            constexpr auto operator()(L&& l, R&& r) const
            noexcept(noexcept(std::forward<L>(l) >> std::forward<R>(r)))
            -> decltype(std::forward<L>(l) >> std::forward<R>(r))
            {
                return std::forward<L>(l) >> std::forward<R>(r);
            }
        };
    
    }
    
    template<class X, class Y> using has_equality = op_valid<X, Y, std::equal_to<>>;
    template<class X, class Y> using has_inequality = op_valid<X, Y, std::not_equal_to<>>;
    template<class X, class Y> using has_less_than = op_valid<X, Y, std::less<>>;
    template<class X, class Y> using has_less_equal = op_valid<X, Y, std::less_equal<>>;
    template<class X, class Y> using has_greater_than = op_valid<X, Y, std::greater<>>;
    template<class X, class Y> using has_greater_equal = op_valid<X, Y, std::greater_equal<>>;
    template<class X, class Y> using has_bit_xor = op_valid<X, Y, std::bit_xor<>>;
    template<class X, class Y> using has_bit_or = op_valid<X, Y, std::bit_or<>>;
    template<class X, class Y> using has_left_shift = op_valid<X, Y, notstd::left_shift>;
    template<class X, class Y> using has_right_shift = op_valid<X, Y, notstd::right_shift>;
    
    int main()
    {
        assert(( has_equality<int, int>() ));
        assert((not has_equality<std::string&, int const&>()()));
        assert((has_equality<std::string&, std::string const&>()()));
        assert(( has_inequality<int, int>() ));
        assert(( has_less_than<int, int>() ));
        assert(( has_greater_than<int, int>() ));
        assert(( has_left_shift<std::ostream&, int>() ));
        assert(( has_left_shift<std::ostream&, int&>() ));
        assert(( has_left_shift<std::ostream&, int const&>() ));
    
        assert((not has_right_shift<std::istream&, int>()()));
        assert((has_right_shift<std::istream&, int&>()()));
        assert((not has_right_shift<std::istream&, int const&>()()));
    }
    

    【讨论】:

      猜你喜欢
      • 2011-01-08
      • 2015-04-27
      • 2019-03-07
      • 2018-09-25
      • 2017-10-09
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2015-11-03
      相关资源
      最近更新 更多