我试图创建一个示例,它将检查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 ( l.a==r.a);
}
#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;
}
Run Code Online (Sandbox Code Playgroud)
是否有可能编写一个测试函数来测试非成员的存在operator==?如果有,怎么样?
顺便说一下,我检查了类似的问题,但没有找到合适的解决方案:
是否可以使用SFINAE /模板来检查操作员是否存在?
这是我试过的:
template <typename C> static yes test( const C*,bool(*)(const C&,constC&) = &operator== );
Run Code Online (Sandbox Code Playgroud)
但如果删除非成员运算符==,编译将失败
iam*_*ind 39
以下技巧有效.它可以用于所有这样的运营商:
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)) };
};
}
Run Code Online (Sandbox Code Playgroud)
用法:
CHECK::EqualExists<A>::value;
Run Code Online (Sandbox Code Playgroud)
第二个template typename Arg对某些特殊情况很有用,例如A::operator==(short),它与class自身不相似.在这种情况下,用法是:
CHECK::EqualExists<A, short>::value
// ^^^^^ argument of `operator==`
Run Code Online (Sandbox Code Playgroud)
演示.
我们不需要使用sizeof技巧decltype
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(std::declval<T>() == std::declval<Arg>)()), No>::value };
};
}
Run Code Online (Sandbox Code Playgroud)
jop*_*rat 16
看看Boost的概念检查库(BCCL)http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm.
它使您能够编写类必须匹配的要求才能编译程序.你可以检查的是相对自由的.例如,验证operator==类Foo 的存在将写如下:
#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
}
Run Code Online (Sandbox Code Playgroud)
只要两个实现中的operator==一个可用,此代码就可以编译.
在@Matthieu M.和@Luc Touraille建议之后,我更新了代码片段以提供使用示例boost::EqualityComparable.请再次注意,EqualityComparable会强制您声明operator!=.
Nic*_*aus 10
也可以只使用c ++ 11类型特征来检查成员的存在:
#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 {};
Run Code Online (Sandbox Code Playgroud)
您可以像这样使用特征:
bool test = has_operator_equal<MyClass>::value;
Run Code Online (Sandbox Code Playgroud)
结果类型has_operator_equal将是std::true_type或std::false_type(因为它继承自别名std::is_same::type),并且都定义了value一个布尔值的静态成员.
如果您希望能够测试您的类是否定义operator==(someOtherType),则可以设置第二个模板参数:
bool test = has_operator_equal<MyClass, long>::value;
Run Code Online (Sandbox Code Playgroud)
其中模板参数MyClass仍然是你的存在测试的类operator==,并且long是要能够比较,如:测试的类型MyClass有operator==(long).
if EqualTo(就像在第一个例子中那样)是未指定的,它将默认为T,导致正常的定义operator==(MyClass).
谨慎的注意:这个特性在的情况下,operator==(long)将是真正的long,或隐式转换的任何值到long,例如double,int等等.
您还可以定义对其他运算符和函数的检查,只需替换其中的内容即可decltype.要检查!=,只需更换
static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>());
Run Code Online (Sandbox Code Playgroud)
同
static auto test(U*) -> decltype(std::declval<U>() != std::declval<V>());
Run Code Online (Sandbox Code Playgroud)
从 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&>()()));
}
Run Code Online (Sandbox Code Playgroud)
我猜您想检查用户提供的模板类型是否具有相等运算符,如果是这种情况,Concepts 可以提供帮助。
#include<concepts>
struct S{
int x;
};
template<class T>
requires std::EqualityComparable<T>
void do_magic(T a, T b){
return a == b;
}
int main(){
// do_magic(S{}, S{}); Compile time error
do_magic(56, 46); // Okay int has == and !=
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您传递任何没有==并!=重载的类型,编译器只会出错并显示消息:
EqualityComparable类型不满足的概念
您还可以使用std::EqualityComparableWith<T, U>概念可以检查两种不同类型之间的重载。
还有更多的概念被添加到标准中,例如Incrementable等等。看看这里