您的位置:首页 > 运维架构

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

2014-08-19 19:43 609 查看

compare a pointer to member?

up vote2down
vote
favorite
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<’"


0
down vote
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 to
A::a
(
int A::*
) with pointer to
A::b
(
float A::*
)、

0
down vote
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、===============================================================================================================================

1
down vote
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.

C++: Pointer to data member address doubt

up vote5down
vote
favorite
2

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 like
if(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).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐