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

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<’"

Pointers to members do not point to some memory themselves. They are just labels. The only thing you can do with them is to convert them to reference to pointee value of the given object with operator.* or->* or store in another pointer to member variable.

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

int & realPointer = a.*p2m;

Note, that you only can compare pointers of the same type, so you can't compare pointer toA::a (int A::*) with pointer toA::b (float A::*)、

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";
2、===============================================================================================================================

While it's true that the a null pointer of type "pointer to member of a given type" must be different from any non-null value of that type, offsetting non-null pointers by one is not the only way that a compiler can ensure this. For example, my compiler uses a non-zero representation of null pointer-to-members.

namespace {
struct a {
    int x, y;
};
}

#include <iostream>

int main() {
    int a::*p = &a::x, a::*q = &a::y, a::*r = nullptr;

    std::cout << "sizeof(int a::*) = " << sizeof(int a::*)
              << ", sizeof(unsigned long) = " << sizeof(long);

    std::cout << "\n&a::x = " << *reinterpret_cast<long*>(&p)
              << "\n&a::y = " << *reinterpret_cast<long*>(&q)
              << "\nnullptr = " << *reinterpret_cast<long*>(&r)
              << '\n';
}

Produces the following output:

sizeof(int a::*) = 8, sizeof(unsigned long) = 8
&a::x = 0
&a::y = 4
nullptr = -1

Your compiler is probably doing something similar, if not identical. This scheme is probably more efficient for most 'normal' use cases for the implementation because it won't have to do an extra "subtract 1" every time you use a non-null pointer-to-member.

3、==============================================================================================

registration required.

I have read(Inside C++ object model) that address of pointer to data member in C++ is the offset of data member plus 1?
I am trying this on VC++ 2005 but i am not getting exact offset values.
For example:

Class X{  
  public:  
    int a;  
    int b;  
    int c;
}

void x(){  
  printf("Offsets of a=%d, b=%d, c=%d",&X::a,&X::b,&X::c);
}  

Should print Offsets of a=1, b=5, c=9. But in VC++ 2005 it is coming out to be a=0,b=4,c=8.
I am not able to understand this behavior.
Excerpt from book:

"That expectation, however, is off by one—a somewhat traditional error for both C and C++ programmers.

The physical offset of the three coordinate members within the class layout are, respectively, either 0, 4, and 8 if the vptr is placed at the end or 4, 8, and 12 if the vptr is placed at the start of the class. The value returned from taking the member's address, however, is always bumped up by 1. Thus the actual values are 1, 5, and 9, and so on.
The problem is distinguishing between a pointer to no data member and a pointer to the first data member. Consider for example:

float Point3d::*p1 = 0;
float Point3d::*p2 = &Point3d::x;

// oops: how to distinguish?
if ( p1 == p2 ) {
cout << " p1 & p2 contain the same value — ";
cout << " they must address the same member!" << endl;
}
To distinguish between p1 and p2, each actual member offset value is bumped up by 1. Hence, both the compiler (and the user) must remember to subtract 1 before actually using the value to address a member."

To complement AndreyT's answer: Try running this code on your compiler.

void test()
{  
    using namespace std;

    int X::* pm = NULL;
    cout << "NULL pointer to member: "
        << " value = " << pm 
        << ", raw byte value = 0x" << hex << *(unsigned int*)&pm << endl;

    pm = &X::a;
    cout << "pointer to member a: "
        << " value = " << pm 
        << ", raw byte value = 0x" << hex << *(unsigned int*)&pm << endl;

    pm = &X::b;
    cout << "pointer to member b: "
        << " value = " << pm 
        << ", raw byte value = 0x" << hex << *(unsigned int*)&pm << endl;
}

On Visual Studio 2008 I get:

NULL pointer to member:  value = 0, raw byte value = 0xffffffff
pointer to member a:  value = 1, raw byte value = 0x0
pointer to member b:  value = 1, raw byte value = 0x4

So indeed, this particular compiler is using a special bit pattern to represent a NULL pointer and thus leaving an 0x0 bit pattern as representing a pointer to the first member of an object.

This also means that wherever the compiler generates code to translate such a pointer to an integer or a boolean, it must be taking care to look for that special bit pattern. Thus something likeif(pm) or the conversion performed by the<< stream operator is actually written by the compiler as a test against the 0xffffffff bit pattern (instead of how we typically like to think of pointer tests being a raw test against address 0x0).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值