Boost logo

Boost :

From: Beman Dawes (bdawes_at_[hidden])
Date: 2006-05-31 15:48:48


me22 wrote:
> On 5/31/06, Beman Dawes <bdawes_at_[hidden]> wrote:
>> The rationale for hiding the templates was that some implementations may
>> prefer to provide hand-coded implementations of each type, either to speed
>> compiles or to achieve platform specific optimizations. (I don't recommend
>> the latter because of a lot of past experience where optimizations became
>> pessimizations when something as simple as a compiler switch changed.)
>>
>
> With templates, specialisation could be used to provide hand-coded
> implementations, if desired.

Yes.

> I fail to see how these would drastically speed compilation while
> remaining header-only, and if an implementation file becomes
> acceptable, explicit instantiation could be easily used for the
> templates that are needed.

Essentially, the implementation hand-generates the same code as would be
generated by template instantiation. Bulky, but not difficult. All
inline, to avoid ODR violations.

At one time avoiding templates, particularly recursive templates, was an
issue. Probably not much of an issue today.

>> I'm often amazed at the clever names Boosters suggest, so I think it is
>> worthwhile to speculate a bit about better names. But the everyday use
>> typedefs really do need to be short and memorable. I've been using the
>> "bin2", "bun3", etc. since 1984 or so, with several hundred programmers now
>> using them all the time, and never had a request to change the names.
>>
>
> * Use the naming conventions of the C++ Standard Library (See
> Naming conventions rationale):
> o Names (except as noted below) should be all lowercase,
> with words separated by underscores.
> o Acronyms should be treated as ordinary names (e.g.
> xml_parser instead of XML_parser).
> o Template parameter names begin with an uppercase letter.
> o Macro (gasp!) names all uppercase and begin with BOOST_.
> * Choose meaningful names - explicit is better than implicit, and
> readability counts. There is a strong preference for clear and
> descriptive names, even if lengthy.
>
> ~ http://boost.org/more/lib_guide.htm#Naming
>
>> The rationale for typedefs is that when an application uses endian classes,
>> they are often used very heavily. Think hundreds, thousands, or even more
>> uses in an organization. So, the names should be short, and all developers
>> should use the same names.
>>
>> struct header_record
>> {
>> bun3 version;
>> bun1 rev;
>> bun5 nrecs;
>> ..... blah blah blah
>> };
>
> In a struct like that, copy-pasting would mean that slightly longer
> names wouldn't be much of an inconvenience:
>
> struct header_record
> {
> unsigned_bigendian<3> version;
> unsigned_bigendian<1> revision;
> unsigned_bigendian<5> record_count;
> };
>
> and I think the readability gain would quickly make up for it. That
> being said, Rene Rivera's suggestions might be a nice middle-ground.

Yes, I'd prefer something more along the lines of Rene's suggestions. If
the template were exposed, people would always be able to write out the
names in full if desired.

> Rene also raises an interesting point about the nessessity of
> operations on the types. How often does the internal byte ordering
> matter when not doing IO?

Never, AFAIK. But the point is that you often read a record containing
values these types, inspect, modify, and then write them back out. So
for any operations not provided, you have to convert to the underlying
type, perform the computation, then convert back. Even if the conversion
is done automatically, you still have to explicitly provide a temporary.
Or write ugly casts.

Also, there isn't any real cost to providing full arithmetic operations.
The functions are never instantiated if they are not used.

>> I guess I shouldn't have used that example, since it isn't realistic. In the
>> real world, the endian classes are almost always used in classes or structs,
>> and the I/O is usually Unix or fstream level rather than iostreams.
>>
> Sorry, but can you explain the difference between "fstream level" and
> "iostreams"?
>
> Also, how do you usually deal with padding?
> struct S {
> boost::bin4 a;
> boost::bun4a b;
> boost::bin5 c, d;
> };
> g++ 3.4.6, for example, gives sizeof(S) as 20.

That's correct, and other compilers will come up with the same result.
Here is a little test program:

#include <iostream>
#include <cstddef>
#include <boost/endian.hpp>

  struct S {
      boost::bin4 a;
      boost::bun4a b;
      boost::bin5 c, d;
  };

int main()
{
   std::cout << sizeof(S) << " "
             << offsetof(S,a) << " "
             << offsetof(S,b) << " "
             << offsetof(S,c) << " "
             << offsetof(S,d) << std::endl;
   return 0;
}

It outputs 20 0 4 8 13.

In other words, 2 padding bytes are added after the d. That ensures that
each element of an array is correctly aligned.

The result would be the same if b was an int, assuming 32-bit int's.
When a struct (or class) has any aligned member, the whole struct gets
aligned accordingly. Using endian.hpp doesn't alter that.

Now change b from bun4a to bun4, and re-run: 18 0 4 8 13. Because no
members are aligned, the struct is not padded.

Thanks,

--Beman


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk