Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a class implements != operator overloading?

Tags:

c++

Given the following function:

template <typename T>
static bool equals(const std::vector<T> &a, const std::vector<T> &b) {
  if (a.size() != b.size())
    return false;

  for (size_t i = 0; i < a.size(); ++i)
    if (a[i] != b[i]) // Requires that the != operator is supported by the template type.
      return false;

  return true;
}

how can I determine if the given T overrides the != operator? If someone uses a type without overloading it might end up using a simple binary comparison which might silently lead to wrong results. So I want to ensure only classes that have their own != operator overloading can be used here.

like image 427
Mike Lischke Avatar asked Jan 06 '23 08:01

Mike Lischke


1 Answers

[update 1 - boost 'semi' solution]

I realized that example from my first answer does not work if your class has conversion operator (to type which allows for != comparision), to fix it you can use boost has_not_equal_to type trait. Still its not perfect, as in some cases it generates compilation error instead of giving a value. Those cases are listed in provided link.

[update 2 - concepts solution]

Example with use of concepts:

#include <iostream>
#include <vector>

template<typename T>
concept bool OperatorNotEqual_comparable()
{
    return requires (T a, T b) {
        { a.operator!=(b) } -> bool;
    };   
}

template <OperatorNotEqual_comparable T>
static bool equals(const std::vector<T> &a, const std::vector<T> &b) {
  if (a.size() != b.size())
    return false;

  for (size_t i = 0; i < a.size(); ++i)
    if (a[i] != b[i]) // Requires that the != operator is supported by the template type.
      return false;

  return true;
}

struct sample1{
    bool operator!=(const sample1&) const { return true; }
};

struct sample2{
};

struct sample3{
    operator void*() { return 0; }
};

int main() {
    // Compiles ok!
    std::vector<sample1> vec1;
    equals(vec1, vec1);

    // Fails, which is OK!
    //std::vector<sample2> vec2;
    //equals(vec2, vec2);    

    // Fails, which is OK!
    //std::vector<sample2*> vec2;
    //equals(vec2, vec2);

    // Fails, which is OK!
    //std::vector<int> vec4;
    //equals(vec4, vec4);        

    // Fails, which is OK!
    //std::vector<sample3> vec5;
    //equals(vec5, vec5);            
}

http://melpon.org/wandbox/permlink/txliKPeMcStc6FhK

[old answer - SFINAE solution, does not check for conversion operator]

You can use SFINAE, and in the near future concepts (they are in gcc 6.0),

#include<iostream>
#include<string>
#include<type_traits>

template<typename T>
class has_not_equal{
    template<typename U>
    struct null_value{
        static U& value;
    };

    template<typename U>
    static std::true_type test(U*,decltype(null_value<U>::value!=null_value<U>::value)* = 0);
    static std::false_type test(void*);

public:
    typedef decltype(test(static_cast<T*>(0))) type;
    static const bool value = type::value;
};

struct sample1{
    bool operator!=(const sample1&) { return true; }
};

struct sample2{
};

int main(){
    std::cout<<std::boolalpha;
    std::cout<<has_not_equal<int>::value<<std::endl;
    std::cout<<has_not_equal<std::string>::value<<std::endl;

    std::cout<<has_not_equal<sample1>::value<<std::endl;
    std::cout<<has_not_equal<sample2>::value<<std::endl;
}

output:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
true
true
true
false

live

above code is a modified version from this site, it was for operator==, I changed it to operator!=

like image 162
marcinj Avatar answered Jan 08 '23 23:01

marcinj