are member pointers fixed in size and reinterpret

I am trying to create a template class that contains a pointer to an arbitrary class instance and function as follows:

template<class C>
class A {
   typedef void (C::*FunctPtr)(); //e.g. void C::some_funct();

   FunctPtr functPtr_;
   C* instPtr_;
public:
   A(FunctPtr functPtr, C* instPtr)
      : functPtr_(functPtr)
      , instPtr_(instPtr) {}
};

However, I want to be able to create instances of this class without dynamic memory allocation using placement new. Does the C++ standard guarantee this template class is of fixed size for all classes C?

In Don Clugston's article on pointers I noticed a chart of the various sizes for member functions pointers on various compilers and a few compilers aren't always the same size. I thought I was hosed but is this standards compliant? From the C++ standard sec. 5.2.10 on Reinterpret cast:

— converting a prvalue of type “pointer to member function” to a different pointer to member function type and back to its original type yields the original pointer to member value.

Would that statement from the C++ standard indicate member function pointers are all of the same size?

If not I suppose I could still rewrite the code as follows to take advantage of that reinterpret_cast guarantee explicitly:

class GenericClass;

template<class C>
class A {

   typedef void (GenericClass::*GenFunctPtr)();
   typedef void (C::*SpecificFunctPtr)();

   GenFunctPtr functPtr_; //store any kind of function ptr in this fixed format
   GenericClass* instPtr_;

public:
   A(SpecificFunctPtr functPtr, C* instPtr)
      : functPtr_(reinterpret_cast<GenFunctPtr>(functPtr))
      , instPtr_(reinterpret_cast<GenericClass*>(instPtr)) {}

   void DoSomething()
   {
      //now convert pointers back to the original type to use...
      reinterpret_cast<SpecificFunctPtr>(functPtr_);
      reinterpret_cast<C*>(instPtr_);
   }
};

This now would seem to be required to be all the same size and yet be standards compliant, right? I'd prefer the first option however if I must the 2nd will also work. Thoughts?


I don't know if the implementation details of pointer-to-member are specified in the standard (can't find it), but since we know that C* will have the same size for all C , we can just determine the size of FunctPtr for various types C and just add a static_assert :

template <class C>
class A {
   typedef void (C::*FunctPtr)(); //e.g. void C::some_funct();
   static_assert(sizeof(FunctPtr) == 16, 
       "unexpected FunctPtr size"); // from coliru, clang and gcc

   FunctPtr functPtr_;
   C* instPtr_;
   ...
};

At least I tried this with several types of classes ({base, derived, multiple derived} x {virtual, non-virtual}) and it always gave the same size.

This is probably platform and/or compiler specific, as Pointers to member functions are very strange animals indicates:

The size of a pointer-to-member-function of a class that uses only single inheritance is just the size of a pointer.
The size of a pointer-to-member-function of a class that uses multiple inheritance is the size of a pointer plus the size of a size_t.

which is not what I see in clang or gcc.


Microsoft compilers use different sizes of member pointers depending on how complex the class is. Technically this isn't compliant (since you can define pointers to members even when the class definition isn't visible), but it works sufficiently well in practice that they do it by default. Pragmas and compiler switches are available to control this behaviour. See for example https://msdn.microsoft.com/en-us/library/83cch5a6.aspx.

Even so the pointers for any given class are always the same size, it's just different classes may have different sized pointers to members.

链接地址: http://www.djcxy.com/p/28758.html

上一篇: 使用const抛出const

下一篇: 是成员指针固定大小和重新解释