3

From the C++ standard:

A standard-layout class is a class that:

— has no non-static data members of type non-standard-layout class (or array of such types) or reference,

— has no virtual functions (10.3) and no virtual base classes (10.1),

— has the same access control (Clause 11) for all non-static data members, — has no non-standard-layout base classes,

— either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and

— has no base classes of the same type as the first non-static data member

The macro offsetof(type, member-designator) accepts a restricted set of type arguments in this International Standard. If type is not a standard-layout class (Clause 9), the results are undefined

Considering these statements is there any safe way of using offsetof for members that depend on template parameters? If not, how may I get the offset of a member in template classes? What might be unsafe when using something like:

//MS Visual Studio 2013 definition
#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))

on non standard layout classes?

Following a sample where is NOT SAFE according to the standard:

#include <cstddef>
#include <iostream>

template<typename T>
struct Test
{
    int     a;
    T       b;
};

struct NonStdLayout
{
    virtual void f(){};
};

int main()
{
    std::cout << offsetof(Test<int>, b) << std::endl;
    std::cout << offsetof(Test<NonStdLayout>, b) << std::endl;
    return 0;
}
Community
  • 1
  • 1
Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211

2 Answers2

1

offsetof cannot be used on non-standard-layout classes simply because their layout in memory is unknown. For example, the standard does not specify how virtual member functions are implemented. One common way of doing so is to add a pointer to the vtable as the first data member of a class, but it's not the only way.

As to your definition of offsetof: there is no guarantee that a null pointer converts to a 0 via reinterpret_cast (or via a C-style cast), neither is there any semantics specified for other values of pointers cast to integers.

So if you know that your definition makes sense in the underlying addressing scheme used by your compiler for your platform, it can work. But it's an if you have to be aware of.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

The answer is that it is perfectly safe to use offsetof in templates. No harm will be done thereby. However, if you choose to do so then you impose a restriction on the type of parameter for the template. It will work correctly for standard layout classes, and in principle at least the compiler should tell you when the parameter is of a type for which it won't work.

There is no way under the standard to obtain the offset for a member of a non-standard-layout class, regardless of whether any template is involved. It will probably work in individual compilers, but it may not. It is likely to work on all non-virtual classes (although this is not a requirement of the standard). Maybe you just have to experiment.

We are frequently forced to write non-standards compliant code to solve problems like this, so we test it carefully on individual compilers. It just means more hard work in research and testing.

david.pfx
  • 10,520
  • 3
  • 30
  • 63