如何检查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_type
或std::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
值 (例如double
, int
等)。
你也可以通过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
在线演示
希望有所帮助。
- entity frameworkCTP 4.“不能将NULL值插入列” – 即使没有NULL值
- C + + cmath与math.h(和类似的C前缀与.h扩展头)
- 如何防止Windows进入闲置状态?
- Windows 7计时function – 如何正确使用GetSystemTimeAdjustment?
- 在服务器上打开IncludeExceptionDetailInFaults(来自ServiceBehaviorAttribute或来自<serviceDebug>configuration行为)
- Ifstring的一个class轮不是空的或空的
- 在C ++中“重新绑定”引用是否合法?
- 我如何获得和设置C#中的环境variables?
- 如何使用C#连接到MS Access文件(mdb)?