Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Offset from member pointer without temporary instance

Tags:

c++

I would like to get the offset of a standard layout member variable when provided with a poiner to that variable. I cannot use offsetof since I have a pointer and not a name. The current code I have looks something like this, and I am wondering if there is a standards compliant way to get rid of the dummy variable.

template<class T>
struct {
  ptrdiff_t get_offset( int (T::*mem) )
  {
    T dummy;
    return reinterpret_cast<char*>(&(dummy.*mem)) 
      - reinterpret_cast<char*>(&dummy);
  }
};

This function should only be callable with int member variable points (this is intentional).

I am quite certain that the compiler doesn't actually create the dummy variable but it'd still be nice if I could get rid of it. I can't use a null pointer since dereferencing null is not defined (though it probably works on all common compilers). A C++03 solution would be good, or a C++11 solution is also of interest (but not usable by me now).

NOTE: I'm already aware this is only standards compliant is T is a standard layout type.

like image 587
edA-qa mort-ora-y Avatar asked Aug 27 '12 11:08

edA-qa mort-ora-y


2 Answers

How about:

template<class T>
struct {
  ptrdiff_t get_offset( int (T::*mem) )
  {
    union {
      int used;
      T unused;
    } dummy;
    return reinterpret_cast<char*>(&(dummy.unused.*mem)) 
      - reinterpret_cast<char*>(&dummy.unused);
  }
};

The address of a union member doesn't depend on the union member being constructed. Works already in C++03, but then only for PODs.

like image 80
MSalters Avatar answered Nov 15 '22 18:11

MSalters


I'm afraid that no standard-compliant solution which satisfies OP requirements exists.

I can give a couple of non-compliant ones.

template<class T>
  size_t get_offset( int (T::*mem) )
    {
    return reinterpret_cast<char*>(&(((T*)nullptr)->*mem))-reinterpret_cast<char*>(nullptr);
    }

It's funny, but the following works in VC2010, making use of offsetof being a macro.

template<class T>
  size_t get_offset( int (T::*mem) )
    {
    return offsetof(T, *mem);
    }
like image 24
Andrey Avatar answered Nov 15 '22 18:11

Andrey