0
struct Sample {
    double value1;
    double value2;
    double value3;
};

double Mean(std::vector<Sample>::const_iterator begin, 
    std::vector<Sample>::const_iterator end,
    double Sample::* var)
{
    float mean = 0;
    int samples = 0;
    for(; begin != end; begin++) {
        const Sample& s = *begin;
        mean += s.*var;
        samples++;
    }
    mean /= samples;
    return mean;
}

...
double mean = Mean(samples.begin(), samples.end(), &Sample::value2);

code copy from C++: Pointer to class data member “::*”

I think this is a good example to show when and how to use pointer to member, but after go to deeper, I find type of var is double Sample::*.

So my question is how this pointer (var) know it bind to value2 not value1 or value3 just because you pass &Sample::value2?

My guess: I think the &Sample::value2 must be special that to indicate pointer var should point to address offset two double. But key point is how to indicate? I have not found any additional information in clang AST. Please help me. Thx.

merito
  • 465
  • 4
  • 15

2 Answers2

1

So my question is how this pointer (var) know it bind to value2 not value1 or value3 just because you pass &Sample::value2?

Because that's what passing &Sample::value2 does.

The key point here is that unlike most pointers, a pointer to member does not refer to a memory location, but to some internal compiler-defined state that refers to which member of the type it refers to.

In practice, that generally simply means a byte offset relative to this.

1

In a typical implementation a pointer of type pointer-to-data-member is implemented exactly as you guessed: it is an offset in bytes from the beginning of the containing object.

In your example var would be implemented as offset in bytes from the beginning of Sample object. Assuming that sizeof(double) is 8 and there's no padding between the fields, your var initialized with &Sample::value2 is actually just offset 8 in disguise. &Sample::value1 would be 0 and &Sample::value3 would be 16.

One curious consequence of this implementational approach is that value 0 is also a "useful" value for such pointers (offset 0 for the very first field), which means that null pointer value of this kind cannot be represented by all-zero bit pattern. Typically implementations use 0xFF...F pattern as null pointer representation in such pointers.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • Thank you. So i can use a pointer of type pointer-to-data/function-member, but seems that a pointer of type pointer-to-overloading-function-member is illegal? Because I can not indicate the pointer should access which function member. – merito Jan 04 '18 at 05:41
  • Pointer to member function is simply the raw address of the function, but pointer to virtual function is interpreted as an offset into the vtable, rather than the object itself. – Gem Taylor Jan 04 '18 at 10:27
  • @GemTaylor overloading function is not virtual, it needn’t a vtable. – merito Jan 05 '18 at 01:41
  • @merito: Pointer-to-data-member and pointer-to-member-function are two very different things. Your questin is about pointer-to-data-member. Pointer-to-member-function typically has significantly more complicated internal structure intended to make it work properly with virtual inheritance and multpile inheritance. – AnT stands with Russia Jan 05 '18 at 02:02
  • @Gem Taylor: If you check typical implementations, you'll notice that pointer-to-member-functions are typically larger than ordinary raw pointers. No, it is not just a raw address and not an offset into vtable. In all cases it is usually a pointer to an internal dispatcher function that redirects the call to the proper recipient. – AnT stands with Russia Jan 05 '18 at 02:05
  • Granted "simply" is an exaggeration: a lot of nastiness goes into getting pointer to member function right. I'm fairly sure there are special cases for pointer to member data to handle virtual base classes as well. – Gem Taylor Jan 05 '18 at 11:50