5

我很困惑为什么不能使用二元运算符比较指向成员的指针<

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

};
和一个模板:

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

当我像下面这样调用 access_order 时:

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

g++ 报告:

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

有没有办法比较指向成员的指针,我的意思是不相等的比较,以及如何?

4

6 回答 6

2

您可以比较对象成员的地址:

A a;
if (std::less<void*>()(&a.a, &a.b))
    std::cout << "a precedes b\n";
else
    std::cout << "a follows b\n";
于 2012-10-25T14:26:31.613 回答
2

最好的选择之一 - 通过 制作原始副本std::memcpy,计算哈希,然后将其用于比较(感谢@HolyBlackCat 的评论)。下面的函数计算传递的指向成员的指针的哈希值(在现代 C++ 17 编译器 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));
}

不幸的是,它不兼容,std::hash<>因为 last 只需要一个模板参数。

如何使用:

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;
}
于 2021-12-24T14:26:34.050 回答
1

出于同样的原因,您通常无法比较指针。唯一支持的顺序比较是两个数据指针是否指向同一个数组。否则,比较的结果是未指定的;编译器不需要以任何合理的方式使运算符“工作”。(确保这里的总顺序需要在某些架构上进行额外的计算。)由于没有任何情况可以为指向成员的指针获得指定的结果,因此标准不允许它们作为运算符的参数。

如果您需要总订购std::less等。保证提供。包括,如果我正确理解标准,成员指针。(尽管为指向成员函数的指针提供总排序可能会非常昂贵。)然而,即使这样,这种排序也可能是任意的;它当然不需要反映内存中的任何顺序。

于 2012-10-25T10:16:21.603 回答
0

指向成员的指针本身并不指向某些内存。它们只是标签。您可以对它们做的唯一事情是将它们转换为使用运算符对给定对象的指针值的引用,.*或者->*存储在另一个指向成员变量的指针中。

struct A
{
    int a;
    float b;
};
A a;
int A::* p2m = &A::a;
int A::* p2m2 = p2m;

int & realPointer = a.*p2m;

请注意,您只能比较相同类型的指针,因此您不能比较指向A::a( int A::*) 的指针和指向A::b( float A::*)的指针

于 2012-10-25T11:00:39.067 回答
0

如果 Point3d 重载 < 然后尊重它们并进行比较,

返回 *mem1 < *mem2 ?"member 1 accurs first": "member 2 accurs first";

或更改签名

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

你想对实际的内存地址进行比较吗?

于 2012-10-25T09:55:28.773 回答
0

指针比较似乎吸引了所有人,但它们总是导致不可移植或未定义的行为。

最简单的答案是你永远不应该这样做。没有经典方法无法解决的计算问题。

不要误会我的意思,我知道提出错误的问题可能会产生有趣的想法,或者更好地理解语言甚至 CPU 的工作原理。

于 2021-12-24T15:21:36.987 回答