Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

compare a pointer to member?

Tags:

c++

I was confused about why can't compare pointers to member using binary operator<

class Point3d{
  protected:
      //..
 public:
     float x;
      static list<Point3d*> *freeList;
 public:
     float y;
     static const int chunkSize = 250;
 public:
    float z;

};
and a template:

template< class class_type, class data_type1, class data_type2 >

char* access_order(data_type1 class_type:: *mem1, data_type2 class_type:: *mem2)
{

    return
      mem1 < mem2 ?
         "member 1 accurs first":
         "member 2 accurs first";
}  

when I called the access_order like below:

access_order(&Point3d::z, &Point3d::y);

the g++ reported:

"invalid operands of types ‘float Point3d::*’ and ‘float Point3d::*’ to binary ‘operator<’"

Is there a way compare pointer to member, I mean the unequal comparison, and how?

like image 542
Fly Avatar asked Oct 06 '22 05:10

Fly


2 Answers

You can compare the addresses of the members of an object:

A a;
if (std::less<void*>()(&a.a, &a.b))
    std::cout << "a precedes b\n";
else
    std::cout << "a follows b\n";
like image 144
Pete Becker Avatar answered Oct 08 '22 20:10

Pete Becker


One of the best option - make a raw copy via std::memcpy, calculate hash and then use it for comparison (thanks @HolyBlackCat for comments). The function below calculates the hash for passed pointer-to-member (tested on modern C++ 17 compilers VS, GCC. CLang).

#include <cstring>
#include <string_view>
#include <functional>

template <typename TObject, typename TMember>
size_t HashMemberPtr(TMember TObject::* memberPtr)
{
    char buf[sizeof memberPtr];
    std::memcpy(&buf, &memberPtr, sizeof memberPtr);
    return std::hash<std::string_view>{}(std::string_view(buf, sizeof buf));
}

Unfortunately it's not compatible with std::hash<> as last requires only one template argument.

How to use:

struct CPoint3D
{
    float x;
    float y;
    float z;
};

int main()
{
    const size_t xHash = HashMemberPtr(&CPoint3D::x);

    assert(xHash == HashMemberPtr(&CPoint3D::x));
    assert(xHash != HashMemberPtr(&CPoint3D::y));
    assert(xHash != HashMemberPtr(&CPoint3D::z));

    return 0;
}
like image 42
Pavel K. Avatar answered Oct 08 '22 18:10

Pavel K.