Class Specialization

I tried to understand the following code but it's not getting into my head.
So can anyone please explain the following lines of code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
template <> // the following is a template class with no templated parameters
class Storage8<bool> // we're specializing Storage8 for bool
{
// What follows is just standard class implementation details
private:
    unsigned char m_tType;
 
public:
    void Set(int nIndex, bool tType)
    {
        // Figure out which bit we're setting/unsetting
        // This will put a 1 in the bit we're interested in turning on/off
        unsigned char nMask = 1 << nIndex;
 
        if (tType)  // If we're setting a bit
            m_tType |= nMask;  // Use bitwise-or to turn that bit on
        else  // if we're turning a bit off
            m_tType &= ~nMask;  // bitwise-and the inverse mask to turn that bit off
    }
 
    bool Get(int nIndex)
    {
        // Figure out which bit we're getting
        unsigned char nMask = 1 << nIndex;
        // bitwise-and to get the value of the bit we're interested in
        // Then implicit cast to boolean
        return m_tType & nMask;
    }
};

This code belongs to Adam. Comments have been written by him.No copyright offense.
Last edited on
The code is out of context; you cannot be expected to understand it.

Specializing templated classes is very similar to specializing templated functions. This example may be more obvious:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T> //just your standard template
T CombineTwoThings(T a, T b)
{
    return a + b; //works for most things, from numbers to std::string
}
template<> //indicates we are creating a specialization
bool CombineTwoThings<bool>(bool a, bool b) //we replace T with the specialized type and indicate the type in the function name
{
    return a || b;
}

//...
CombineTwoThings(1, 2); //calls the first version, returns 3
CombineTwoThings<short>(1, 2); //calls the first version, returns 3
CombineTwoThings(true, false); //calls the second version, returns true
CombineTwoThings<bool>(false, false); //calls the second version, returns false 


With classes it is basically the same:
1
2
3
4
5
6
7
8
9
10
template<typename T>
class MyClass
{
    //class definition for T
};
template<>
class MyClass<std::string>
{
    //class definition for std::string
};
MyClass<int>, MyClass<float>, etc. all refer to the first version, but MyClass<std::string> will use the second version.

That's the basics.
Last edited on
Since you haven't provided the declaration for Storage8<>, it's difficult to tell what that template provides or why it's being used since what you've provided appears to be self contained.

What you've provided is a simple class that gets, sets or clears a bit in m_tType.
Do you understand how the two functions work?
@LB thanks for the example..
@AbstractAnon That's what I am not able to understand. I know the basics of
bitwise AND(&) , bitwise OR(|) , bitwise XOR(^) and bitwise NOT(~). But how is that used to set the bits in those get/set functions , I don't understand.

This line confuses me the most:
 
 unsigned char nMask = 1 << nIndex;

closed account (zb0S216C)
[Note: There can be no partial specialisation of a function of any kind. --end note]

Raman009 wrote:
"But how is that used to set the bits in those get/set functions , I don't understand."

The lines are commented, so what are you not comfortable with?

Raman009 wrote:
"This line confuses me the most:

unsigned char nMask = 1 << nIndex;"

This is a shift-left operation. It's commonly used to index the bits of a byte. Just like arrays, shifting 1 to the left by 1 will reference the second bit of the byte. For instance:

1
2
3
4
5
6
7
enum
{
    BIT_1 = (1 << 0),
    BIT_2 = (1 << 1),
    BIT_3 = (1 << 2),
    // ...
};

In addition, shifting to the left is equivalent to multiplication by powers of two, and shifting to the right is equivalent to dividing by powers of two.

Wazzak
@Framework..why is unsigned char used here ?
I know it gives a range from 0 to 255.(characters) How does that make any difference ?

int can be used to have the same functionality ie to set the bits on or off OR to determine whether any bit is on or off. Isn't it ?

It saves one additional step when dealing with int ie
1
2
3
4
5
6
7
unsigned char bitPattern = 3;
/*do some processing 
.....
.....
.....
*/
cout << static_cast<int>(bitPattern) << endl;
Last edited on
closed account (zb0S216C)
Raman009 wrote:
"How does that make any difference ?"

Because the last bit of a signed integer (normally the most significant bit) is used to indicate whether or not the value is positive (LOW) or negative (HIGH). The remaining 7 bits are used to represent the actual value [127 maximum]. Because bit-flag values are almost never negative, "unsigned" is used instead for a larger range of possible bit-flag values.

Raman009 wrote:
"int can be used to have the same functionality ie to set the bits on or off OR to determine whether any bit is on or off. Isn't it ?"

Any integral type is suitable.

Wazzak
Last edited on
thanks a lot @Framework
Topic archived. No new replies allowed.