Related
I am trying to create an example, which would check the existence of the operator== (member or, non-member function). To check whether a class has a member operator== is easy, but how to check whether it has a non-member operator==?
This is what I have to far :
#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;
}
Is it possible to write a test function to test the existence of non-member operator==?
If yes, how?
btw I have checked similar questions, but haven't found a proper solution :
Is it possible to use SFINAE/templates to check if an operator exists?
This is what I tried :
template <typename C> static yes test( const C*,bool(*)(const C&,constC&) = &operator== );
but the compilation fails if the non-member operator== is removed
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
Have a look at Boost's Concept Check Library (BCCL) http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm.
It enables you to write requirements that a class must match in order for the program to compile. You're relatively free with what you can check. For example, verifying the presence of operator== of a class Foo would write as follow:
#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
}
This code compiles fine as long as one of the two implementations of operator== is available.
Following #Matthieu M. and #Luc Touraille advice, I updated the code snippet to provide an example of boost::EqualityComparable usage. Once again, please note that EqualityComparable forces you to declare operator!= too.
It's also possible to use only c++11 type traits to check the existence of the member:
#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 {};
You can use the trait like so:
bool test = has_operator_equal<MyClass>::value;
The resulting type of has_operator_equal will either be std::true_type or std::false_type (because it inherits from an alias of std::is_same::type), and both define a static value member which is a boolean.
If you want to be able to test whether your class defines operator==(someOtherType), you can set the second template argument:
bool test = has_operator_equal<MyClass, long>::value;
where the template parameter MyClass is still the class that you are testing for the presence of operator==, and long is the type you want to be able to compare to, e.g. to test that MyClass has operator==(long).
if EqualTo (like it was in the first example) is left unspecified, it will default to T, result in the normal definition of operator==(MyClass).
Note of caution: This trait in the case of operator==(long) will be true for long, or any value implicitly convertible to long, e.g. double, int, etc.
You can also define checks for other operators and functions, just by replacing what's inside the decltype. To check for !=, simply replace
static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>());
with
static auto test(U*) -> decltype(std::declval<U>() != std::declval<V>());
C++20
I guess you want to check whether a user-provided type has equality operator or not; if that is the case then Concepts are here to help.
#include <concepts>
struct S{
int x;
};
template<std::equality_comparable T>
bool 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 !=
}
If you pass any type that does not have == and != defined, the compiler just errors out with message, e.g.:
equality_comparable concept not satisfied by type
You can also use std::equality_comparable_with<T, U> concept to check for those overload between two different types.
There are many more concepts that have been added to standards such as std::incrementable etc.. Have a look at Standard Library concepts as a good starting point.
As of c++14, the standard binary functions do most of the work for us for the majority of operators.
#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&>()()));
}
I know this question has long since been answered but I thought it might be worth noting for anyone who finds this question in the future that Boost just added a bunch of "has operator" traits to their type_traits library, and among them is has_equal_to, which does what OP was asking for.
This question has already been answered several times, but there is a simpler way to check for the existence of operator== or basically any other operation (e.g., testing for a member function with a certain name), by using decltype together with the , operator:
namespace detail
{
template<typename L, typename R>
struct has_operator_equals_impl
{
template<typename T = L, typename U = R> // template parameters here to enable SFINAE
static auto test(T &&t, U &&u) -> decltype(t == u, void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<L>(), std::declval<R>()));
};
} // namespace detail
template<typename L, typename R = L>
struct has_operator_equals : detail::has_operator_equals_impl<L, R>::type {};
You can use this same approach to check if a type T has a member function foo which is invocable with a certain argument list:
namespace detail
{
template<typename T, typename ...Args>
struct has_member_foo_impl
{
template<typename T_ = T>
static auto test(T_ &&t, Args &&...args) -> decltype(t.foo(std::forward<Args>(args)...), void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<T>(), std::declval<Args>()...));
};
} // namespace detail
template<typename T, typename ...Args>
struct has_member_foo : detail::has_member_foo_impl<T, Args...>::type {};
I think this makes the intent of the code much clearer. In addition to that, this is a C++11 solution, so it doesn't depend on any newer C++14 or C++17 features. The end result is the same, of course, but this has become my preferred idiom for testing these kinds of things.
Edit: Fixed the insane case of the overloaded comma operator, I always miss that.
Lets consider a meta-function of the following form, which checks for the existence of equality operator (i.e ==) for the given type:
template<typename T>
struct equality { .... };
However, that might not be good enough for some corner cases. For example, say your class X does define operator== but it doesn't return bool, instead it returns Y. So in this case, what should equality<X>::value return? true or false? Well, that depends on the specific use case which we dont know now, and it doesn't seem to be a good idea to assume anything and force it on the users. However, in general we can assume that the return type should be bool, so lets express this in the interface itself:
template<typename T, typename R = bool>
struct equality { .... };
The default value for R is bool which indicates it is the general case. In cases, where the return type of operator== is different, say Y, then you can say this:
equality<X, Y> //return type = Y
which checks for the given return-type as well. By default,
equality<X> //return type = bool
Here is one implementation of this meta-function:
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> {};
Test:
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;
}
Output:
equality<A>::value = 0
equality<B>::value = 1
equality<C>::value = 0
equality<B,short>::value = 0
equality<C,short>::value = 1
Online Demo
Hope that helps.
c++17 slightly modified version of Richard Hodges godbolt
#include <functional>
#include <type_traits>
template<class T, class R, class ... Args>
std::is_convertible<std::invoke_result_t<T, Args...>, R> is_invokable_test(int);
template<class T, class R, class ... Args>
std::false_type is_invokable_test(...);
template<class T, class R, class ... Args>
using is_invokable = decltype(is_invokable_test<T, R, Args...>(0));
template<class T, class R, class ... Args>
constexpr auto is_invokable_v = is_invokable<T, R, Args...>::value;
template<class L, class R = L>
using has_equality = is_invokable<std::equal_to<>, bool, L, R>;
template<class L, class R = L>
constexpr auto has_equality_v = has_equality<L, R>::value;
struct L{};
int operator ==(int, L&&);
static_assert(has_equality_v<int>);
static_assert(!has_equality_v<L>);
static_assert(!has_equality_v<L, int>);
static_assert(has_equality_v<int, L>);
In addition to #coder3101 answer, concepts can help you implement any function existence tests you want to. For example, std::equality_comparable is implemented using 4 simple tests, that check the following scenarios:
For A and B variables, make sure that the following expressions are valid:
A == B, returns bool
A != B, returns bool
B == A, returns bool
B != A, returns bool
If any one of them is illegal at compile time, the program won't compile. The implementation of this test (simplified from the standard):
template <typename T> concept equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ t != u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
{ u != t } -> std::convertible_to<bool>;
};
As you can see, you can customize this concept and create your own concept the fulfill your conditions. For example, if you want to force only the existence of operator==, you can do something like this:
template <typename T> concept my_equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
};
Read more about concepts in C++20.
We can use std::equal_to<Type> (or any other overloaded struct members) to make a more generic solution if we want to test binary operators (or other binary functors).
struct No {};
template<class T, class BinaryOperator>
struct ExistsBinaryOperator>
{
enum { value = !std::is_same<decltype(std::declval<BinaryOperator>()(std::declval<T>(), std::declval<T>())), No>::value };
};
Usage:
using Type = int;
constexpr bool hasEqual = ExistsBinaryOperator<Type, std::equal_to<Type>>::value;
This should work on C++11
template <class Void, template<class...> class Type, class... Args>
struct validator
{
using value_t = std::false_type;
};
template <template<class...> class Type, class... Args>
struct validator< std::void_t<Type<Args...>>, Type, Args... >
{
using value_t = std::true_type;
};
template <template<class...> class Type, class... Args>
using is_valid = typename validator<void, Type, Args...>::value_t;
template<typename... T>
using has_equal_t = decltype((std::declval<T&>().operator ==(std::declval<T&>()), ...));
template<typename... T>
using has_gequal_t = decltype((operator ==(std::declval<T&>(),std::declval<T&>()), ...));
struct EQ
{
bool operator==(const EQ&) const;
};
struct GEQ
{
};
bool operator==(const GEQ&, const GEQ&);
struct NOEQ
{
};
static_assert(is_valid<has_equal_t,EQ>::value || is_valid<has_gequal_t,EQ>::value, "should have equal operator");
static_assert(is_valid<has_equal_t,GEQ>::value || is_valid<has_gequal_t,GEQ>::value, "should have equal operator");
// static_assert(is_valid<has_equal_t,NOEQ>::value || is_valid<has_gequal_t,NOEQ>::value, "should have equal operator"); // ERROR:
Just for a reference, I am posting how I solved my problem, without a need to check if the operator== exists :
#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==r.a ) && ( b==r.b ) );
}
#endif
};
#if 1
bool operator==( const A &l,const A &r )
{
std::cout<<"calling NON-member function"<<std::endl;
return ( ( l.a==r.a ) &&( l.b==r.b ) );
}
#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( l.p, r.p, 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;
}
IMO, this must be part of the class itself as it's deals with the private attributes of the class. The templates are interpreted at compile time. By default it generates operator==,constructor, destructor and copy constructor which do bit-wise copy (shallow copy) or bit-wise comparisons for the object of same type. The special cases (different types) must be overloaded. If you use global operator function you will have to declare the function as friend to access the private part or else you've to expose the interfaces required. Sometimes this is really ugly which may cause an unnecessary expose of a function.
There is a nice question (Which substitution failures are not allowed in requires clauses?) proposing the next problem.
One needs to write a compile-time function template<typename... Ts> constexpr bool allTypesUnique() that will return true if all argument types are unique, and false otherwise. And the restriction is not to compare the argument types pairwise. Unfortunately, the answer only explains why such function cannot be implemented with some particular approach.
I think the solution can be achieved using multiple inheritance. The idea is to make a class inherited from a number of classes: one for each type T in Ts. And each such class defines a virtual function with a signature depending on T. If some T is found more than once in Ts then function f in a child class will override the function in a base class and it can be detected:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
using B<Ts...>::f;
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename T>
struct B<T> {
constexpr virtual void f(A<T>, bool & unique) { if( ++count > 1 ) unique = false; }
int count = 0;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
B<Ts...> b;
bool res = true;
( b.f( A<Ts>{}, res ), ... );
return res;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/8jhnE7P11
Just curious, is the solution correct and is there a simpler solution for this problem?
A simpler solution can be obtained in compilers supporting class size optimization via C++20 attribute [[no_unique_address]] for empty members. If all class empty members have distinct types, then its sizeof will be 1. If some member types are repeating then they cannot share the same address and sizeof will be more than 1.
Solution code:
template<typename> struct A{};
template<typename T, typename... Ts>
struct B : B<Ts...> {
[[no_unique_address]] A<T> a;
};
template<typename T>
struct B<T> {
[[no_unique_address]] A<T> a;
};
template<typename... Ts>
constexpr bool allTypesUnique() {
if constexpr (sizeof...(Ts) <= 1 )
return true;
else
return sizeof(B<Ts...>) == 1;
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int&>() );
static_assert( !allTypesUnique<int&, int&>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo: https://gcc.godbolt.org/z/577EP1774
A single constexpr function can be constructed to answer this question:
template <class T, class... Ts>
constexpr bool unique_types()
{
if constexpr (sizeof...(Ts)) {
return !(std::is_same_v<T,Ts> || ...) && unique_types<Ts...>();
}
return true;
}
Demo
the code above is the compile time equivalent of
for (int i(0); i < n; ++i)
for (int j(i + 1); j < n; ++j)
{ /* check type[i] vs type[j] */ }
If you want any variation in comparison (e.g. consider int same as int&) just modify the std::is_same_v (e.g. std::is_same_v<std::decay_t<T>, std::decay_t<Ts>>)
If you use virtual base classes depending on each of the given types, you will get exact one base class instance for every unique type in the resulting class. If the number of given types is the number of generated base classes, each type was unique. You can "measure" the number of generated base classes by its size but must take care that you have a vtable pointer inside which size is implementation dependent. As this, each generated type should be big enough to hide alignment problems.
BTW: It works also for reference types.
template < typename T> struct AnyT { char i[128]; };
template < typename FIRST, typename ... T>
struct CheckT: virtual AnyT<FIRST>, virtual CheckT<T...> { };
template < typename FIRST >
struct CheckT<FIRST>: virtual AnyT<FIRST> {};
template < typename ... T>
constexpr bool allTypesUnique()
{
using T1 = CheckT<int>;
using T2 = CheckT<bool, int>;
constexpr std::size_t s1 = sizeof( T1 );
constexpr std::size_t s2 = sizeof( T2 );
constexpr std::size_t diff = s2 - s1;
constexpr std::size_t base = s1 - diff;
constexpr std::size_t measure = sizeof( CheckT< T...> );
return !((sizeof...(T)*diff+base) - measure);
}
int main() {
static_assert( allTypesUnique<void>() );
static_assert( allTypesUnique<void, int>() );
static_assert( !allTypesUnique<void, void>() );
static_assert( allTypesUnique<char, short, int>() );
static_assert( !allTypesUnique<char, short, char>() );
}
Demo
I think you can try to elaborate on using compile-time type ids.
Here is a partly implemented C++14 version (compile-time sorting is required):
#include <cstddef>
#include <type_traits>
#include <utility>
namespace detail {
template<typename T>
struct type_id {
constexpr static int value{};
};
template<const int *const A, const int *const B>
struct same_address : std::false_type {};
template<const int *const A>
struct same_address<A, A> : std::true_type {};
}// namespace detail
// TODO: implement
template<const int *const... I>
struct sort_array {
using type = std::integer_sequence<const int *const, I...>;
};
template<typename>
struct find_duplicates;
template<const int *const A, const int *const B, const int *const... I>
struct find_duplicates<std::integer_sequence<const int *const, A, B, I...>> {
constexpr static bool value = std::conditional_t<detail::same_address<A, B>::value,
std::true_type,
find_duplicates<std::integer_sequence<const int *const, B, I...>>>::value;
};
template<>
struct find_duplicates<std::integer_sequence<const int *const>> {
constexpr static bool value = false;
};
template<const int *const I>
struct find_duplicates<std::integer_sequence<const int *const, I>> {
constexpr static bool value = false;
};
template<typename... T>
constexpr bool all_types_unique() {
return !find_duplicates<typename sort_array<&detail::type_id<T>::value...>::type>::value;
};
int main() {
static_assert(detail::same_address<&detail::type_id<int>::value,
&detail::type_id<int>::value>::value,
"");
static_assert(!detail::same_address<&detail::type_id<int>::value,
&detail::type_id<double>::value>::value,
"");
static_assert(all_types_unique<>(), "");
static_assert(all_types_unique<int>(), "");
static_assert(all_types_unique<int, double>(), "");
static_assert(all_types_unique<int, double, char>(), "");
static_assert(!all_types_unique<int, int>(), "");
static_assert(!all_types_unique<int, int, int>(), "");
return 0;
}
https://godbolt.org/z/E4G6YchE5
I am trying to find a way to compare boost::variant with underlying value without constructing variant from this underlying value. The question is defined in the comment in "main()" function
And auxiliary question is about the comparison operators defined in the code. How to decrease the # of comparison operators? If boost::variant contains, say, 6 different types, do I have to define 6! operators to be able to compare two variants?
Thanks!
#include <boost/variant.hpp>
namespace test {
namespace Tag {
struct Level1{ int t{ 1 }; };
struct Level2{ int t{ 2 }; };
}
template <typename Kind> struct Node;
using LevelOne = Node<Tag::Level1>;
using LevelTwo = Node<Tag::Level2>;
using VariantNode = boost::variant
<
boost::recursive_wrapper<LevelOne>,
boost::recursive_wrapper<LevelTwo>
>;
typedef VariantNode* pTree;
typedef std::vector<pTree> lstTree;
template <typename Kind> struct Node
{
Node(pTree p, std::string n) : parent(p), name(n) {}
Node(const Node& another) : name(another.name), parent(another.parent) {}
virtual ~Node() {}
std::string name;
pTree parent;
};
bool operator == (const LevelOne& one, const LevelTwo& two) {
return false;
}
bool operator == (const LevelTwo& two, const LevelOne& one) {
return false;
}
bool operator == (const LevelOne& one, const LevelOne& two) {
return true;
}
bool operator == (const LevelTwo& one, const LevelTwo& two) {
return true;
}
}
int main(int argc, char *argv[])
{
using namespace test;
LevelOne l1(nullptr, "level one");
VariantNode tl2 = VariantNode(LevelTwo(nullptr, "level two"));
VariantNode tl1 = VariantNode(LevelOne(nullptr, "level one"));
bool rv = (tl1 == tl2); // this line compiles OK (comparing two variants)
// comparison below does not compile, because "l1" is not a variant.
// Question: How can I compare "variant" value "tl1"
// with one of the possible content values "l1"
bool rv1 = (tl1 == l1);
return 1;
}
The following will work with any number of types in the variant:
template<typename T>
struct equality_visitor : boost::static_visitor<bool> {
explicit constexpr equality_visitor(T const& t) noexcept : t_{ &t } { }
template<typename U, std::enable_if_t<std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const& u) const {
return *t_ == u;
}
template<typename U, std::enable_if_t<!std::is_same<T, U>::value>* = nullptr>
constexpr bool operator ()(U const&) const {
return false;
}
private:
T const* t_;
};
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator ==(T const& t, boost::variant<Ts...> const& v) {
equality_visitor<T> ev{ t };
return v.apply_visitor(ev);
}
template<
typename T,
typename... Ts,
typename = std::enable_if_t<
boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
>
>
bool operator !=(T const& t, boost::variant<Ts...> const& v) {
return !(t == v);
}
The catch is that comparisons must always be of the form value == variant or value != variant rather than variant == value or variant != value. This is because boost::variant<> itself defines these operators to always static_assert, and there is no way for us to make a global operator more specialized than variant<>'s built-in ones.
Online Demo
I am trying to create an example, which would check the existence of the operator== (member or, non-member function). To check whether a class has a member operator== is easy, but how to check whether it has a non-member operator==?
This is what I have to far :
#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;
}
Is it possible to write a test function to test the existence of non-member operator==?
If yes, how?
btw I have checked similar questions, but haven't found a proper solution :
Is it possible to use SFINAE/templates to check if an operator exists?
This is what I tried :
template <typename C> static yes test( const C*,bool(*)(const C&,constC&) = &operator== );
but the compilation fails if the non-member operator== is removed
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
Have a look at Boost's Concept Check Library (BCCL) http://www.boost.org/doc/libs/1_46_1/libs/concept_check/concept_check.htm.
It enables you to write requirements that a class must match in order for the program to compile. You're relatively free with what you can check. For example, verifying the presence of operator== of a class Foo would write as follow:
#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
}
This code compiles fine as long as one of the two implementations of operator== is available.
Following #Matthieu M. and #Luc Touraille advice, I updated the code snippet to provide an example of boost::EqualityComparable usage. Once again, please note that EqualityComparable forces you to declare operator!= too.
It's also possible to use only c++11 type traits to check the existence of the member:
#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 {};
You can use the trait like so:
bool test = has_operator_equal<MyClass>::value;
The resulting type of has_operator_equal will either be std::true_type or std::false_type (because it inherits from an alias of std::is_same::type), and both define a static value member which is a boolean.
If you want to be able to test whether your class defines operator==(someOtherType), you can set the second template argument:
bool test = has_operator_equal<MyClass, long>::value;
where the template parameter MyClass is still the class that you are testing for the presence of operator==, and long is the type you want to be able to compare to, e.g. to test that MyClass has operator==(long).
if EqualTo (like it was in the first example) is left unspecified, it will default to T, result in the normal definition of operator==(MyClass).
Note of caution: This trait in the case of operator==(long) will be true for long, or any value implicitly convertible to long, e.g. double, int, etc.
You can also define checks for other operators and functions, just by replacing what's inside the decltype. To check for !=, simply replace
static auto test(U*) -> decltype(std::declval<U>() == std::declval<V>());
with
static auto test(U*) -> decltype(std::declval<U>() != std::declval<V>());
C++20
I guess you want to check whether a user-provided type has equality operator or not; if that is the case then Concepts are here to help.
#include <concepts>
struct S{
int x;
};
template<std::equality_comparable T>
bool 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 !=
}
If you pass any type that does not have == and != defined, the compiler just errors out with message, e.g.:
equality_comparable concept not satisfied by type
You can also use std::equality_comparable_with<T, U> concept to check for those overload between two different types.
There are many more concepts that have been added to standards such as std::incrementable etc.. Have a look at Standard Library concepts as a good starting point.
As of c++14, the standard binary functions do most of the work for us for the majority of operators.
#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&>()()));
}
I know this question has long since been answered but I thought it might be worth noting for anyone who finds this question in the future that Boost just added a bunch of "has operator" traits to their type_traits library, and among them is has_equal_to, which does what OP was asking for.
This question has already been answered several times, but there is a simpler way to check for the existence of operator== or basically any other operation (e.g., testing for a member function with a certain name), by using decltype together with the , operator:
namespace detail
{
template<typename L, typename R>
struct has_operator_equals_impl
{
template<typename T = L, typename U = R> // template parameters here to enable SFINAE
static auto test(T &&t, U &&u) -> decltype(t == u, void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<L>(), std::declval<R>()));
};
} // namespace detail
template<typename L, typename R = L>
struct has_operator_equals : detail::has_operator_equals_impl<L, R>::type {};
You can use this same approach to check if a type T has a member function foo which is invocable with a certain argument list:
namespace detail
{
template<typename T, typename ...Args>
struct has_member_foo_impl
{
template<typename T_ = T>
static auto test(T_ &&t, Args &&...args) -> decltype(t.foo(std::forward<Args>(args)...), void(), std::true_type{});
static auto test(...) -> std::false_type;
using type = decltype(test(std::declval<T>(), std::declval<Args>()...));
};
} // namespace detail
template<typename T, typename ...Args>
struct has_member_foo : detail::has_member_foo_impl<T, Args...>::type {};
I think this makes the intent of the code much clearer. In addition to that, this is a C++11 solution, so it doesn't depend on any newer C++14 or C++17 features. The end result is the same, of course, but this has become my preferred idiom for testing these kinds of things.
Edit: Fixed the insane case of the overloaded comma operator, I always miss that.
Lets consider a meta-function of the following form, which checks for the existence of equality operator (i.e ==) for the given type:
template<typename T>
struct equality { .... };
However, that might not be good enough for some corner cases. For example, say your class X does define operator== but it doesn't return bool, instead it returns Y. So in this case, what should equality<X>::value return? true or false? Well, that depends on the specific use case which we dont know now, and it doesn't seem to be a good idea to assume anything and force it on the users. However, in general we can assume that the return type should be bool, so lets express this in the interface itself:
template<typename T, typename R = bool>
struct equality { .... };
The default value for R is bool which indicates it is the general case. In cases, where the return type of operator== is different, say Y, then you can say this:
equality<X, Y> //return type = Y
which checks for the given return-type as well. By default,
equality<X> //return type = bool
Here is one implementation of this meta-function:
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> {};
Test:
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;
}
Output:
equality<A>::value = 0
equality<B>::value = 1
equality<C>::value = 0
equality<B,short>::value = 0
equality<C,short>::value = 1
Online Demo
Hope that helps.
c++17 slightly modified version of Richard Hodges godbolt
#include <functional>
#include <type_traits>
template<class T, class R, class ... Args>
std::is_convertible<std::invoke_result_t<T, Args...>, R> is_invokable_test(int);
template<class T, class R, class ... Args>
std::false_type is_invokable_test(...);
template<class T, class R, class ... Args>
using is_invokable = decltype(is_invokable_test<T, R, Args...>(0));
template<class T, class R, class ... Args>
constexpr auto is_invokable_v = is_invokable<T, R, Args...>::value;
template<class L, class R = L>
using has_equality = is_invokable<std::equal_to<>, bool, L, R>;
template<class L, class R = L>
constexpr auto has_equality_v = has_equality<L, R>::value;
struct L{};
int operator ==(int, L&&);
static_assert(has_equality_v<int>);
static_assert(!has_equality_v<L>);
static_assert(!has_equality_v<L, int>);
static_assert(has_equality_v<int, L>);
In addition to #coder3101 answer, concepts can help you implement any function existence tests you want to. For example, std::equality_comparable is implemented using 4 simple tests, that check the following scenarios:
For A and B variables, make sure that the following expressions are valid:
A == B, returns bool
A != B, returns bool
B == A, returns bool
B != A, returns bool
If any one of them is illegal at compile time, the program won't compile. The implementation of this test (simplified from the standard):
template <typename T> concept equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ t != u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
{ u != t } -> std::convertible_to<bool>;
};
As you can see, you can customize this concept and create your own concept the fulfill your conditions. For example, if you want to force only the existence of operator==, you can do something like this:
template <typename T> concept my_equality_comparable
= requires(T t, T u) {
{ t == u } -> std::convertible_to<bool>;
{ u == t } -> std::convertible_to<bool>;
};
Read more about concepts in C++20.
We can use std::equal_to<Type> (or any other overloaded struct members) to make a more generic solution if we want to test binary operators (or other binary functors).
struct No {};
template<class T, class BinaryOperator>
struct ExistsBinaryOperator>
{
enum { value = !std::is_same<decltype(std::declval<BinaryOperator>()(std::declval<T>(), std::declval<T>())), No>::value };
};
Usage:
using Type = int;
constexpr bool hasEqual = ExistsBinaryOperator<Type, std::equal_to<Type>>::value;
This should work on C++11
template <class Void, template<class...> class Type, class... Args>
struct validator
{
using value_t = std::false_type;
};
template <template<class...> class Type, class... Args>
struct validator< std::void_t<Type<Args...>>, Type, Args... >
{
using value_t = std::true_type;
};
template <template<class...> class Type, class... Args>
using is_valid = typename validator<void, Type, Args...>::value_t;
template<typename... T>
using has_equal_t = decltype((std::declval<T&>().operator ==(std::declval<T&>()), ...));
template<typename... T>
using has_gequal_t = decltype((operator ==(std::declval<T&>(),std::declval<T&>()), ...));
struct EQ
{
bool operator==(const EQ&) const;
};
struct GEQ
{
};
bool operator==(const GEQ&, const GEQ&);
struct NOEQ
{
};
static_assert(is_valid<has_equal_t,EQ>::value || is_valid<has_gequal_t,EQ>::value, "should have equal operator");
static_assert(is_valid<has_equal_t,GEQ>::value || is_valid<has_gequal_t,GEQ>::value, "should have equal operator");
// static_assert(is_valid<has_equal_t,NOEQ>::value || is_valid<has_gequal_t,NOEQ>::value, "should have equal operator"); // ERROR:
Just for a reference, I am posting how I solved my problem, without a need to check if the operator== exists :
#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==r.a ) && ( b==r.b ) );
}
#endif
};
#if 1
bool operator==( const A &l,const A &r )
{
std::cout<<"calling NON-member function"<<std::endl;
return ( ( l.a==r.a ) &&( l.b==r.b ) );
}
#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( l.p, r.p, 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;
}
IMO, this must be part of the class itself as it's deals with the private attributes of the class. The templates are interpreted at compile time. By default it generates operator==,constructor, destructor and copy constructor which do bit-wise copy (shallow copy) or bit-wise comparisons for the object of same type. The special cases (different types) must be overloaded. If you use global operator function you will have to declare the function as friend to access the private part or else you've to expose the interfaces required. Sometimes this is really ugly which may cause an unnecessary expose of a function.
I would like to define a simple template function which takes a runtime value and determines if it is a member of some set of possible values.
Usage:
int x; // <- pretend this came from elsewhere...
if (isoneof(x, {5,3,9,25}) ...
Something like:
template <typename T, size_t size>
bool isoneof(T value, T (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
I assume that this is doomed to failure, as I don't see how one can create a static array inline.
I can use:
int kPossibilities[] = {5,3,9,25};
if (isoneodf(6, kPossibilities)) ...
With a minor change to isoneof:
template <typename T1, typename T2, size_t size>
bool isoneof(T1 value, const T2 (&arr)[size])
{
for (size_t i = 0; i < size; ++i)
if (value == arr[i])
return true;
return false;
}
Which also makes it a tad more flexible.
Does anyone have an improvement to offer? A better way to define a "set of static values inline"?
If you like such things, then you will be a very happy user of Boost.Assign.
Boost.Assign actually proves that such semantics are possible, however one look at the source of assign will convince you that you don't want to do that by yourself :)
You will be able to create something like this however:
if (isoneof(x, list_of(2)(3)(5)(7)(11)) { ...
... the downside being you'd have to use boost::array as the parameter instead of a built-in array (thanks, Manuel) -- however, that's a nice moment to actually start using them :>
It's possible in the next C++ standard.
Up till then, you can work around it by e.g. overloading operator, for a static object that starts a static array.
Note: this implementation is O(n^2) and may be optimized - it's just to get the idea.
using namespace std;
template< typename T, size_t N >
struct CHead {
T values[N];
template< typename T > CHead<T,N+1> operator,( T t ) {
CHead<T,N+1> newhead;
copy( values, values+N, newhead.values);
newhead.values[N]=t;
return newhead;
}
bool contains( T t ) const {
return find( values, values+N, t ) != values+N;
}
};
struct CHeadProto {
template< typename T >
CHead<T,1> operator,( T t ) {
CHead<T,1> h = {t};
return h;
}
} head;
int main()
{
assert( (head, 1,2,3,4).contains(1) );
return 0;
}
For the sake of completeness, I'll post a solution that uses Boost.MPL. The following works, but I think Kornel's solution is best.
#include <iostream>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector_c.hpp>
struct Contains
{
Contains(int value, bool& result) : value(value), result(result)
{
result = false;
}
template< typename T > void operator()(T x)
{
result = result || (x == value);
}
int value;
bool& result;
};
template <class IntList>
bool isoneof(int val)
{
namespace mpl = boost::mpl;
bool result;
mpl::for_each<IntList>(Contains(val, result));
return result;
}
int main()
{
namespace mpl = boost::mpl;
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(4) << "\n";
std::cout << isoneof< mpl::vector_c<int, 1,2,3,5,7,11> >(5) << "\n";
}
As you can see, the compile-time array is passed inline as a template argument to isoneof.
This one?
int ints[] = {2,3,5,7,11};
#define ARRAY_SIZE(Array) (sizeof(Array)/sizeof((Array)[0]))
#define INLIST(x,array) isoneof(x,array,ARRAY_SIZE(array))
ADDITION:
template <typename T>
bool isoneof(const T& x, T *array, int n)
{
for(int i=0; i<n; ++i)
if(x==array[i])
return true;
return false;
}
Using C++11, this would be written like this:
template <typename T>
bool isoneof(T value, std::initializer_list<T> arr)
{
using namespace std;
return any_of(begin(arr), end(arr), [&](const T& x) { return x == value; });
}
Just FYI - I solved my particular problem using vararg templates and initializer lists now that I have access to C++14:
template <typename T, typename U>
bool isoneof(T v, U v1) { return v == v1; }
template <typename T, typename U, typename... Args>
bool isoneof(T v, U v1, Args ... others) { return isoneof(v, v1) || isoneof(v, others...); }
template <typename T, typename U>
bool isoneof(T value, std::initializer_list<U> values)
{
for (const auto & e : values)
if (value == e)
return true;
return false;
}