F
Francesco S. Carta
The article is not very precise. It doesn't exclude some types,
for instance (non-object types, etc.).
Which are the non-object types?
And when T is not a POD, there can be padding before t in
I have skimmed the standard and I only found a mention about the fact
that a POD type cannot have initial padding, does that suffice to imply
that non-POD types can actually have initial padding or is there some
other explicit reference in the standard?
struct Foo { T t ; char c ; } ;
or even before c in
struct Foo { char c ; T t ; } ;
In the latter case, though, that's unlikely.
FWIW, I'm using a similar technique for "computing" a suitable
alignment down in my (experimental) version of fallible<> (the
non-experimental version has a T member and requires
default-construction, just like the Barton& Nackman one; the
new version drops the default-constructible requirement and uses
placement new---using, of course, a "suitably aligned" array of
unsigned chars).
Copy-pasting from there (beware: I have yet to review it---and
it started as a quick experiment):
template< typename T>
struct align_of
{
struct trick { // gps how to name it?
char c ;
T t ;
} ;
enum { v = sizeof( trick ) - sizeof( T ) } ;
enum { has_padding_at_end = v> sizeof( T ) } ; // should name
// this better
static std::size_t const value = has_padding_at_end
? sizeof( T )
: v
;
} ;
template< typename T>
std::size_t const
align_of< T>::value ;
When T is a POD the whole trick structure (which contains only a
T and a char) is a POD as well: thus there can't be padding
before the first member. (And I find it slightly clearer if the
char appears first.)
When T is not a POD, that padding is allowed. I see no reason
for the compiler to exploit that possibility with the struct
above. Anyway, if it is that "capricious" the whole thing breaks
down (numerical "coincidences" apart ).
I suppose you could compute the initial padding by subtracting the
address of the object from the address of the first member - assuming
that is doable and useful...
Of course, this template is not exposed: it's only used
internally, to try one after another the POD types in a
predefined "list", in order to find the first of them (if any)
that has the same alignment as the type T on which fallible<> is
instantiated (more precisely: for which align_of<>::value is the
same as align_of< T>::value). At the end of the dance, it
doesn't matter what the alignment really is, numerically: it
picks the POD and puts it in the same union that contains the
array of unsigned chars.
Another thing I found perplexing in the article was
template<typename T>
struct Tchar {
T t;
char c;
};
#define strideof(T) \
((sizeof(Tchar<T>)> sizeof(T)) ? \
sizeof(Tchar<T>)-sizeof(T) : sizeof(T))
How can ever be the size of the struct be smaller than, or even
equal to, sizeof( T )? [footnote]
[footnote] I'm aware that in some cases an object may be
"smaller than its type" (virtual base classes etc.) but in this
case...
The author of that macro explains what (and why) has been addressed by
that ternary test: it's something about a possible and presumably
illegal padding reuse, I reported it also in the other replies to the
message you have just quoted from me.