views:

93

answers:

2

Let's say I have 3 classes. I expect sizeof() each class to be exactly the same--say 512 bytes.

How can I use something like BOOST_STATIC_ASSERT to apply to all of them such that

  1. I only need to use BOOST_STATIC_ASSERT in a single place (DRY principle)
  2. Evaluated once at compile-time and not run-time

Note: we can use whatever C++ techniques we want (create more class , use inheritance, etc)

My naive solution is presented below:

class A { ...stuff }; BOOST_STATIC_ASSERT( sizeof(A) == 512 );
class B { ...stuff }; BOOST_STATIC_ASSERT( sizeof(B) == 512 );
class C { ...stuff }; BOOST_STATIC_ASSERT( sizeof(C) == 512 );
+9  A: 

This seems to work with gcc 4.0.1 and boost 1.39:


template <typename T, size_t S>
struct enforce_size
{
    enforce_size()
    {
        BOOST_STATIC_ASSERT( sizeof( T ) == S );
    }
};

class A: enforce_size<A,512> { /* stuff */ };

Nikolai N Fetissov
+1, very clean.
GMan
+1 : You've been faster than me :D
Klaim
Though the error message needs some work :)
Nikolai N Fetissov
Well done, Nikolai.
Shmoopty
Nikolai: by doing it that way, for each time class A is instantiated, does it pay for the BOOST_STATIC_ASSERT cost?
ShaChris23
The cost is at compile time for each separate derivation. There is no run-time cost to this (assuming the compiler does empty base optimization.)
Nikolai N Fetissov
+1  A: 

As those classes have no relationship, I see now way to do this because you have to be explicit about witch types you want to be checked.

The only DRY way to enforce this is what Nikolai N Festissov proposed. I was writting a similar example with some minor modifications, but the global idea is to make a boost::nocopy - like class that will force the child class to be of a given size.

template< typename CheckedType, size_t FixedSize >
class SizeChecked // simple, no inheritance overload
{
public:
    SizeChecked()
    {
     // c++0x or compilers with static_assert() available
     //static_assert( sizeof( CheckedType ) == FixedSize, "Type size check failed!" );
     BOOST_STATIC_ASSERT( sizeof( CheckedType ) == FixedSize );
    }

};

template< typename CheckedType >
class Size512 : public SizeChecked< CheckedType, 512 > // simple, no inheritance overload
{}; 

////////////////////////////////////////////////////////////////////

class A : Size512< A > // automatically check
{
};


class B : Size512< B > // automatically check
{
    std::array< char, 512 > m_array;
};

class C : SizeChecked< C, 1 >
{
    char m_char;
};

class D : SizeChecked< D, 4 >
{
    short m_k;
    char m_u;

};


int wmain()
{
    // need instantiation to be checked !
    //A a; // will trigger the assertion at compile time
    B b; // sizeof(B) == 512 : will be fine
    C c; // sizeof(C) == 1 : will be fine
    //D d; // will fail because sizeof( short ) + sizeof( char ) != 4 !

}

Beware : if you loose inheritance you still have to provide an explicit check on the child classes, the check is not inherited!

By the way, a possible way to be more DRY would be to put all your static assertion in only one place.

Klaim