1

The current run-time implementation is as below:

#define ASSERT_LAST_Member(Class, Member)  {Class foo; assert(((size_t)(&foo) + sizeof(foo)) == ((size_t)(&foo.Member) + sizeof(foo.Member)));}

How can I do static assert while compiling? I've tried to do this, but it didn't work.

#define assert_static(e) \
   do { \
      enum { assert_static__ = 1/(e) }; \
      } while (0)
#define ASSERT_LAST_Member(Class, Member) { assert_static(((size_t)&((Class*)0)->Member)+sizeof(((Class*)0)->Member)==sizeof(Class)) }
pixar
  • 43
  • 1
  • 5
  • 3
    Asserting that a data member is the last one is a code smell. There's something wrong with the design. Are you by any chance trying to place a dynamic size array at the end of a struct? – Cheers and hth. - Alf Jun 05 '14 at 15:04
  • Saying that "it didn't work" is vague. See http://stackoverflow.com/questions/how-to-ask. – jarmod Jun 05 '14 at 15:10
  • In case I add another member in this class(such as protocol) and there are many place to do something with the new member, ASSERT_LAST_Member can make sure nothing is missed. – pixar Jun 05 '14 at 15:11
  • It did not work means: g++ produced many errors error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression error: '->' cannot appear in a constant-expression error: '&' cannot appear in a constant-expression – pixar Jun 05 '14 at 15:12
  • Note that the current implementation is not always correct. E.g.: `ASSERT_LAST_Member(X, y)` is likely to fail on `struct X { int x; char y; };` because of the padding. – Csq Jun 05 '14 at 15:12
  • @Cheersandhth.-Alf "..is a code smell." And a pretty rank one at that. (+1) – WhozCraig Jun 05 '14 at 15:15
  • @Csq, You are right. In my situation, all protocol classes are packed by 1. – pixar Jun 05 '14 at 15:17

1 Answers1

1

You can't really assert that a member is the last of its class today. The proposals in response to N3814 might make this possible, once accepted and implemented, but they're not available today. With what is currently available, you're still sunk because of padding issues (see Csq's example in the comments).

If you ignore that the limitations of padding, and limit yourself to "plain old data" cases without virtual inheritance, you can probably use the offsetof macro, or suggestions from How to calculate offset of a class member at compile time? to perform the check you desire.

But in practice, per your comment about all your classes being protocol classes, can you not just do an assert against the known class size? It wouldn't catch cases when members were reordered, or when an addition fit within padding. But static asserts are really only there to prevent accidental incorrect changes, and you claim not to use padding. So go simple:

static_assert(sizeof(Foo) == 12, "Size of Foo has changed");
Community
  • 1
  • 1
Michael Urman
  • 15,737
  • 2
  • 28
  • 44