
Michael Shepanski wrote:
The code below fails a compile-time assertion in boost 1.32.0 on MSVC 7.1.
class D { virtual ~D(); };
class E : virtual public D { virtual ~E(); unsigned long long m_i; };
FYI: The following article by Tom Lokovic explains a technique for calculating the alignment of a data type. His technique is exactly the same used by boost::alignment_of<>, so we can consider the article an explanation of how alignment_of<> works. http://www.monkeyspeak.com/alignment/ Basically: ********** Explanation of alignment_of<> ********************** Appendix 1 of the article contains a proof of the following interesting claim: "For every type T, sizeof(T) is an integer multiple of T's stride S" (Tom calls "stride of T" to the "alignment requirements of T") Read the proof if you're not convinced. It basically says that C/C++ compilers chooses sizeof(T) as a multiple of the alignment of T because that allows you to arrange instances of T one right after another in an array without violating T's alignment requirements. And Appendix 2 contains a proof of: "For every struct type T, sizeof(T) is an integer multiple of the stride of each of T's members" It basically says that when the compiler creates an object containing both T and U, it must give it a size such that, if 2 instances of the T+U are placed one after another in an array, each member T or U must be itself properly aligned, and for that, the total size must be a multiple of each member's alignment. So, Say we have a type 'T' and we form a new type, Tchar, adding a 'char' to it. Now say we put 2 instances of Tchar into an array. However the char is added into Tchar, the T member of the second Tchar must be properly aligned w.r.t to T's requirement, so the compiler needs to arrange Tchar as to guarantee that. Furhtermore, since a char can be placed anywhere in memory, that is, it's alignment is 1, we know that the compiler has really just 2 choices: either it reuses the padding within T to store the 'char', in which case sizeof(T)==sizeof(Tchar), or it extends the storage needed by an amount equivalent to the alignment of T, or a multiple of that (it has to be like that to make sure each T member is properly placed in an array of Tchar) That is, sizeof(Tchar)-sizeof(T) must be a multiple of the alignment of T. boost::alignment_of<> returns either sizeof(T) or sizeof(Tchar)-sizeof(T), and both are required to be multiples of the alignment of T. It uses the following template to generate Tchar template <typename T> struct alignment_of_hack { char c; T t; alignment_of_hack(); }; ********** End of Explanation of alignment_of<> ********************** Now, I checked some facts with your E class in VC7.1 and the results are interesting: The sizeof(E) is 20 And according to the explanation of how to calculate the alignment of E, a struct adding a 'char' to E should have a size larger than 20 in an amount multiple of the alignment of T. struct Echar { E e ; char c; } ; struct charE { char c; E e ; } ; sizeof(Echar) -> 24 sizeof(charE) -> 32 As you can see, the true alignment of T is 4, while 12 is just 3 times that. As you know by now, the real problem here is that type_with_alignment<> cannot really take as argument "any" multiple of the alignment becasue it cannot match any multiple with its type list. As Martin Bonner suggested, one solution is to factorize the result of alignment_of<> so it returns not just any multiple. Unfortunately, we can't say that the alignment _ought_ to be a power of 2 can we? An alternative solution that, at least, would work with this very specific example, is to compute it as the minimun of sizeof(charT)-sizeof(T) and sizeof(Tchar)-sizeof(T) That is, adding the char both before and after, and taking the least difference. HTH -- Fernando Cacciola SciSoft http://fcacciola.50webs.com/