How to Check Whether Operator== Exists

How to check whether operator== exists?

C++03

The following trick works and it can be used for all such operators:

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)) };
};
}

Usage:

CHECK::EqualExists<A>::value;

The 2nd template typename Arg is useful for some special cases like A::operator==(short), where it's not similar to class itself. In such cases the usage is:

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

Demo.



C++11

We need not use sizeof and null reference trick when we have decltype and std::declval

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 };
};
}

Demo

How to use sfinae to check, whether type has operator ()?

Encouraged by a positive feedback, I will post a brief answer here.

The problem is that you cannot define a class twice, but you did this two times :-

template <typename T>
struct function_traits { .... some code ..... }

C++ doesn't allow that.

To check whether a function is exist, there is already a question about it, you can modify it to support the operator().

Here is a demo, very-slightly modified from Nicola Bonelli's answer there.

#include <iostream>

struct Hello
{
void operator()() { }
};

struct Generic {};

// SFINAE test
template <typename T>
class has_parenthesis
{
typedef char one;
typedef long two;

template <typename C> static one test( decltype(&C::operator()) ) ;
template <typename C> static two test(...);

public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

int main(int argc, char *argv[])
{
std::cout << has_parenthesis<Hello>::value << std::endl; //print 1
std::cout << has_parenthesis<Generic>::value << std::endl; //print 0
return 0;
}

I just knew a few minutes ago that it also works for operator().

Edit: I changed typeof to decltype as StoryTeller and LmTinyToon recommended. Thank.

best way to check for existence of an operator in c++11

Quick-and-dirty C++11 SFINAE:

template<typename T,
typename = decltype(
std::declval<std::ostream&>() << std::declval<T const&>()
)
>
std::string toString(T const& t)
{
std::ostringstream out;
// Beware of no error checking here
out << t;
return out.str();
}

template<typename T,
typename... Ignored
>
std::string toString(T const& t, Ignored const&..., ...)
{
static_assert( sizeof...(Ignored) == 0
, "Incorrect usage: only one parameter allowed" );
/* handle any which way here */
}

If you want you can also check that the return type of stream << val is indeed convertible to std::ostream&:

template<typename T,
typename Result = decltype(
std::declval<std::ostream&>() << std::declval<T const&>()
),
typename std::enable_if<
std::is_convertible<Result, std::ostream&>::value,
int
>::type = 0
>

As for a not so quick-and-dirty solution I'd introduce an is_stream_insertable trait, which implementation can make use of the very same tricks used here.

Be aware that std::integral_constant<bool, B> has a conversion operator to bool, this might explain some of the things you have observed. I also do not recommend mixing the C++11 Standard types and traits with Boost: don't mix up std::true_type with boost::true_type! Which is not to say that you shouldn't use e.g. Boost.TypeTraits at all with C++11, but try to be consistent and only use one of two at a time.

Is it possible to use SFINAE/templates to check if an operator exists?

I ended up using a fallback namespace :

namespace operators_fallback {
template <typename T>
inline QDataStream& operator<<(QDataStream& s, const T &) { return s; }

template <typename T>
inline QDataStream& operator>>(QDataStream& s, T &) { return s; }

template <typename T>
inline QDebug operator<<(QDebug d, const T &) { return d; }
};

...
inline void load(QDataStream & s) {
using namespace operator_fallback;
s >> item;
}

Also found the proper way to check for operators at compile time (although I'm going with the fallback namespace).

more or less based on this :

namespace private_impl {
typedef char yes;
typedef char (&no)[2];

struct anyx { template <class T> anyx(const T &); };

no operator << (const anyx &, const anyx &);
no operator >> (const anyx &, const anyx &);


template <class T> yes check(T const&);
no check(no);

template <typename StreamType, typename T>
struct has_loading_support {
static StreamType & stream;
static T & x;
static const bool value = sizeof(check(stream >> x)) == sizeof(yes);
};

template <typename StreamType, typename T>
struct has_saving_support {
static StreamType & stream;
static T & x;
static const bool value = sizeof(check(stream << x)) == sizeof(yes);
};

template <typename StreamType, typename T>
struct has_stream_operators {
static const bool can_load = has_loading_support<StreamType, T>::value;
static const bool can_save = has_saving_support<StreamType, T>::value;
static const bool value = can_load && can_save;
};
}
template<typename T>
struct supports_qdatastream : private_impl::has_stream_operators<QDataStream, T> {};

template<typename T>
struct can_load : private_impl::has_loading_support<QDataStream, T> {};

template<typename T>
struct can_save : private_impl::has_saving_support<QDataStream, T> {};

template<typename T>
struct can_debug : private_impl::has_saving_support<QDebug, T> {};

//edit changed has_stream_operators a bit.

//edit removed the link, apparently the site has some attack javascript.

does int have an operator==

int is not a class-type and has no member operator==, which is what you check for with your &C::operator==. Thus, the test yields a "no". As others correctly pointed out, your test would also be negative for classes with only a non-member operator==.

How to correctly check whether an operator== exists has been asked here:
How to check whether operator== exists?

Check if class/struct has a specific operator

This kind of traits type almost always takes the following form:

#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;
}

Here is an almost-complete suite of binary operator checkers with some tests.

You should get the general idea. Note that I had to create left_shift and right_shift function objects since these don't exist in the standard library already.

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

is it possible to check if overloaded operator<< for type or class exists?

You could add trait (is_streamable) like this:

#include <type_traits>

// A helper trait to check if the type supports streaming
template<class T>
class is_streamable {

// match if streaming is supported
template<class TT>
static auto test(int) ->
decltype( std::declval<std::ostream&>() << std::declval<TT>(), std::true_type() );

// match if streaming is not supported:
template<class>
static auto test(...) -> std::false_type;

public:
// check return value from the matching "test" overload:
static constexpr bool value = decltype(test<T>(0))::value;
};

template<class T>
inline constexpr bool is_streamable_v = is_streamable<T>::value;

You could then use it like this:

template<class T>
static void serialize_storage(const void* this_, std::ostream& stream) {
if constexpr (is_streamable_v<T>) {
stream << (*reinterpret_cast<const T*>(this_));
} else {
throw std::runtime_error("Type can not be serialized");
}
}

Demo

Check if an character is an operator

This line:

if (o == '%' || '/' || '*' || '+' || '-'){

should be:

if (o == '%' || o == '/' || o == '*' || o == '+' || o == '-'){


Related Topics



Leave a reply



Submit