如何检查operator ==是否存在?

我想创build一个例子,这将检查operator== (成员或非成员函数)的存在。 要检查一个类是否有成员operator==很容易,但是如何检查它是否有一个非成员operator==

这就是我所需要的:

 #include <iostream> struct A { int a; #if 0 bool operator==( const A& rhs ) const { return ( a==rhs.a); } #endif }; #if 1 bool operator==( const A &l,const A &r ) { return ( la==ra); } #endif template < typename T > struct opEqualExists { struct yes{ char a[1]; }; struct no { char a[2]; }; template <typename C> static yes test( typeof(&C::operator==) ); //template <typename C> static yes test( ???? ); template <typename C> static no test(...); enum { value = (sizeof(test<T>(0)) == sizeof(yes)) }; }; int main() { std::cout<<(int)opEqualExists<A>::value<<std::endl; } 

是否有可能编写一个testing函数来testing非成员operator==的存在? 如果是的话,怎么样?

btw我检查了类似的问题,但还没有find一个合适的解决scheme:
是否有可能使用SFINAE /模板来检查运营商是否存在?

这是我试过的:

 template <typename C> static yes test( const C*,bool(*)(const C&,constC&) = &operator== ); 

但如果非成员运算符==被删除,则编译失败

C ++ 03

以下的技巧作品。 它可以用于所有这些运营商:

 namespace CHECK { class No { bool b[2]; }; template<typename T, typename Arg> No operator== (const T&, const Arg&); bool Check (...); No& Check (const No&); template <typename T, typename Arg = T> struct EqualExists { enum { value = (sizeof(Check(*(T*)(0) == *(Arg*)(0))) != sizeof(No)) }; }; } 

用法:

 CHECK::EqualExists<A>::value; 

第二个template typename Arg对于像A::operator==(short)这样A::operator==(short)特殊情况非常有用,它与class本身并不相似。 在这种情况下,用法是:

 CHECK::EqualExists<A, short>::value // ^^^^^ argument of `operator==` 

演示 。


C ++ 11

当我们有decltype时,我们不需要使用sizeof技巧

 namespace CHECK { struct No {}; template<typename T, typename Arg> No operator== (const T&, const Arg&); template<typename T, typename Arg = T> struct EqualExists { enum { value = !std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value }; }; } 

演示

查看Boost的概念检查库 (BCCL) http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm

它使您能够编写要使程序编译的类必须匹配的要求。 你可以检查的东西相对自由。 例如,validationFoo类的operator==的存在将会写成如下:

 #include <boost/concept_check.hpp> template <class T> struct opEqualExists; class Foo { public: bool operator==(const Foo& f) { return true; } bool operator!=(const Foo& f) { return !(*this == f); } // friend bool operator==(const Foo&, const Foo&); // friend bool operator!=(const Foo&, const Foo&); }; template <class T> struct opEqualExists { T a; T b; // concept requirements BOOST_CONCEPT_USAGE(opEqualExists) { a == b; } }; /* bool operator==(const Foo& a, const Foo& b) { return true; // or whatever } */ /* bool operator!=(const Foo& a, const Foo& b) { return ! (a == b); // or whatever } */ int main() { // no need to declare foo for interface to be checked // declare that class Foo models the opEqualExists concept // BOOST_CONCEPT_ASSERT((opEqualExists<Foo>)); BOOST_CONCEPT_ASSERT((boost::EqualityComparable<Foo>)); // need operator!= too } 

只要operator==的两个实现之一可用,此代码就可以编译。

继@Matthieu M.和@Luc Touraillebuild议后,我更新了代码片段,以提供boost::EqualityComparable用法的示例。 请再次注意,EqualityComparable强制您声明operator!=

也可以仅使用c ++ 11types特征来检查成员的存在:

 #include <type_traits> #include <utility> template<class T, class EqualTo> struct has_operator_equal_impl { template<class U, class V> static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>()); template<typename, typename> static auto test(...) -> std::false_type; using type = typename std::is_same<bool, decltype(test<T, EqualTo>(0))>::type; }; template<class T, class EqualTo = T> struct has_operator_equal : has_operator_equal_impl<T, EqualTo>::type {}; 

你可以像这样使用特质:

 bool test = has_operator_equal<MyClass>::value; 

has_operator_equal的结果types将是std::true_typestd::false_type (因为它inheritance了std::is_same::type的别名),并且都定义了一个静态value成员,它是一个布尔值。


如果你想能够testing你的类是否定义了operator==(someOtherType) ,你可以设置第二个模板参数:

 bool test = has_operator_equal<MyClass, long>::value; 

其中模板参数MyClass仍然是您正在testingoperator==的类的testing类,而long则是您希望能够比较的types,例如用于testingMyClass具有operator==(long)

如果EqualTo (就像在第一个例子中)没有被指定,它将默认为T ,导致operator==(MyClass)的正常定义。

请注意 :在operator==(long)的情况下,这个特性将operator==(long)为真,或者任何可隐式转换long (例如doubleint等)。


你也可以通过replacedecltype里面的内容来定义其他操作符和函数的检查。 要检查!= ,只需更换

 static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>()); 

 static auto test(U*) -> decltype(std::declval<U>() != std::declval<V>()); 

我知道这个问题早已得到答案,但我认为值得注意的是任何人在将来都会发现这个问题,Boost只是在type_traits库中增加了一堆“有操作符”的特征,其中有has_equal_to ,做OP是要求的。

从c ++ 14开始,标准的二进制函数为大多数操作员完成了大部分工作。

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

只是作为参考,我张贴如何解决我的问题,而不需要检查operator==存在:

 #include <iostream> #include <cstring> struct A { int a; char b; #if 0 bool operator==( const A& r ) const { std::cout<<"calling member function"<<std::endl; return ( ( a==ra ) && ( b==rb ) ); } #endif }; #if 1 bool operator==( const A &l,const A &r ) { std::cout<<"calling NON-member function"<<std::endl; return ( ( la==ra ) &&( lb==rb ) ); } #endif namespace details { struct anyType { template < class S > anyType( const S &s ) : p(&s), sz(sizeof(s)) { } const void *p; int sz; }; bool operator==( const anyType &l, const anyType &r ) { std::cout<<"anyType::operator=="<<std::endl; return ( 0 == std::memcmp( lp, rp, l.sz ) ); } } // namespace details int main() { A a1; a1.a=3;a1.b=0x12; A a2; a2.a=3;a2.b=0x12; using details::operator==; std::cout<< std::boolalpha << "numbers are equals : " << ( a1 == a2 ) <<std::endl; } 

国际海事组织,这必须是类的一部分,因为它是处理类的私有属性。 模板在编译时解释。 默认情况下,它会生成operator== ,构造函数,析构函数和复制构造函数,它们对相同types的对象进行按位复制(浅拷贝)或按位比较。 特殊情况(不同types)必须超载。 如果使用全局运算符函数,则必须将函数声明为朋友才能访问私有部分,否则必须公开所需的接口。 有时这真的很丑,可能会导致不必要的function暴露。

让我们考虑以下forms的元函数,它检查给定types是否存在相等运算符(即== ):

 template<typename T> struct equality { .... }; 

但是,这可能不够好的一些angular落案件。 例如,假设你的类X定义了operator==但是它不返回bool ,而是返回Y 所以在这种情况下, equality<X>::value返回什么? false ? 那么,这取决于我们现在不知道的具体用例,假设任何东西并强迫用户看起来不是一个好主意。 但是,一般来说,我们可以假设返回types应该是bool ,所以让我们在接口本身中expression:

 template<typename T, typename R = bool> struct equality { .... }; 

R的默认值是bool ,表示这是一般情况。 如果operator==的返回types不同,比如Y ,那么你可以这样说:

 equality<X, Y> //return type = Y 

它也检查给定的返回types。 默认,

 equality<X> //return type = bool 

这是这个元函数的一个实现:

 namespace details { template <typename T, typename R, typename = R> struct equality : std::false_type {}; template <typename T, typename R> struct equality<T,R,decltype(std::declval<T>()==std::declval<T>())> : std::true_type {}; } template<typename T, typename R = bool> struct equality : details::equality<T, R> {}; 

testing:

 struct A {}; struct B { bool operator == (B const &); }; struct C { short operator == (C const &); }; int main() { std::cout<< "equality<A>::value = " << equality<A>::value << std::endl; std::cout<< "equality<B>::value = " << equality<B>::value << std::endl; std::cout<< "equality<C>::value = " << equality<C>::value << std::endl; std::cout<< "equality<B,short>::value = " << equality<B,short>::value << std::endl; std::cout<< "equality<C,short>::value = " << equality<C,short>::value << std::endl; } 

输出:

 equality<A>::value = 0 equality<B>::value = 1 equality<C>::value = 0 equality<B,short>::value = 0 equality<C,short>::value = 1 

在线演示

希望有所帮助。