> it is probably wiser not to hold the seperator string (_sep) as a pointer; this might get us into trouble if a temporary was passed as the second constructor arg
>> But I thought because it's const that can't ever happen.
binary<int> to_binary( int n )
{
char does_not_exist_once_fn_returns[] = "\n" ;
binary<int> ret( n, sep ) ;
return ret ;
}
when the function returns, lifetime of does_not_exist_once_fn_returns is over, but the returned object will hold the pointer. also, as in this example a non-const can be converted implicitly to a const.
> the hard coded assumption that CHAR_BITS==8 should be done away with
>> Isn't a byte always 8 bits? And a nybble is 4 bits?
in common usage, yes. but not as per the C standard. to quote it:
byte: The unit of storage in the execution environment large enough to hold any member of the basic character set of the execution environment. ... A byte is composed of a contiguous sequence of bits, the number of which is implementation-defined.
-- ISO/IEC 9899:1990(E) right on page 2
and the C++ standard is compatible with the C standard for the memory model of POD types.
>> you lost me with the enum and digits thing
C and cplusplus provide library headers (<limits.h> in C, <limits> in C++) which allow us to write correct code inspite of implementation differences. for a numeric type T, std::numeric_limits<T>::radix gives the radix and std::numeric_limits<T>::digits gives the number of digits to base radix.
so, numeric_limits<unsigned char>::digits gives the number of digits (bits) in an unsigned char. if we want to be pedantic, we could assert that numeric_limits<unsigned char>::radix == 2 (, but we do not need to because of C compatibility requirements). it is also possible to use the manifest constant CHAR_BITS from <climits> in place of our enum char_bits. ah, the things we need to do because we program to real (not virtual) machines.
> we could reuse the functionality available in std::bitset<>
>> Now I'm completely lost.
std::bitset<N> represents a sequence of N bits. a bitset<> is output streamable (gives a sequence of 0/1) and can be converted to and from a string. it can also be constructed using a unsigned long. in a bitset<N>, bit 0 is the least significant bit and bit N-1 is the most significant bit; It doesn't depend on the endianness of the hardware platform. (that is one less detail we have to take care of.) another advantage we get with bitset<> is that someone trying to use the binary<T> generalisation, where T is not (or implicitly convertible to) a numeric type would get a compile time error.
> and we can enable assignment by making the member variables non-const
>> I thought it was better to make everything const except the stuff that can't be. So I've been wrong the whole time about that?
you certailnly are not wrong about that; infact that notion is something that would be your friend whenever you write code. but it would be easier (and more flexible) to treat a non-mutable binary<T> as a
const binary<T> rather than a binary<T> with const members. for example
struct person
{
const string name ; // name cannot be changed
string address ; // address can change
bool operator== ( const person& that ) const ;
// both const qualifiers are required for const-correctness
};
but when in doubt, always favour adding a const qualifier (over dropping it).