Template for endianness-free code, data always packed as BIG-Endian
Your code is good, except for two methods : operator unsigned() const and self_t&amp; operator=(unsigned m). They are too complex, and by just looking at them, it is far from clear what they are doing.

First, you can add new values to your enum :

enum {
    lastBit = firstBit + bitSize - 1,
    mask = (1 &lt;&lt; bitSize) - 1,
    firstBitIndex = 8 - (firstBit &amp; 7),                         // change to proper name
    nameThisValueProperly = (7 - (lastBit &amp; 7)) &amp; mask,         // change to proper name
};


First modify your operator unsigned() const to this :

inline operator unsigned() const
{
    const uchar *arr = selfArray();
    const uchar *p = arr + firstBit / 8;

    unsigned result = CalculateSomeValue( p );

    return (result &gt;&gt; nameThisValueProperly );
}

// name this method properly
inline unsigned CalculateSomeValue( const uchar *p ) const
{
    int i = firstBitIndex;
    unsigned result = *p;

    while (i &lt; bitSize)
    {
        result &lt;&lt;= 8;
        result |= *(++p);
        i += 8;
    }

    return result;
}


Of course, you need to put proper names both for enum values and method names, so when someone looks into this code says "Aha, that is what is is doing". This way, you can easy increase code clarity.

Also, by making method smaller, you can easily test them.

More about this method, you can read in Clean code by Robert Martin.

You can do something similar for the self_t&amp; operator=(unsigned m). Break it up, until you find it clean.