2016-09-06 9 views
2

テンプレートの1つを特殊化する必要があり、利用可能な演算子に応じてそれを実行したいと考えています。私は基本的に私は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 
    ... 
} 

を行うことができますかどうかを知る必要があり

は、標準では類似した何かを持っていますか?そうでない場合は、どうすれば実装できますか?

+3

あなたはここで見ていますか? http://stackoverflow.com/questions/6534041/how-to-check-whether-operator-exists – Hayt

+0

いいえ、私はありませんでした、リンクのおかげで。 –

答えて

3

形質のこの種のは、ほとんどの場合、以下の形式をとる入力します。ここでは

#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関数オブジェクトは標準ライブラリには存在しないので、作成する必要があります。 C++ 17では

#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&>()())); 
} 
2

、それは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

関連する問題