ACCU Home page ACCU Conference Page ACCU 2017 Conference Registration Page
Search Contact us ACCU at Flickr ACCU at GitHib ACCU at Google+ ACCU at Facebook ACCU at Linked-in ACCU at Twitter Skip Navigation

pinAddendum to "Tiny Template Tidbit"

Overload Journal #54 - Apr 2003 + Programming Topics   Author: Oliver Schoenborn

I would like to add a few comments to the Overload 47 article that I wrote, entitled "Tiny Template Tidbit". They don't change conclusions of the article but may prevent some confusion.

First, as kindly pointed out to me by Alan Griffiths and Chris Main, I misuse the term "partial specialization".

On page 16, 2nd column, I say "what we need is a template overload for pointers". No problem so far. I then explain briefly that it is somewhat like partial specialization available for classes but not the same. Unfortunately, the code examples contain C++ comments that describe some syntax as "partial specialization" applied to functions (not supported in C++). They should instead read "overload for ...". I must have had a few beers too many that day.

Secondly, a minor mistake in the formatting of the two lines "Advantages:" and "Disadvantages:". The typeface makes it look like there are three paragraphs of advantages and almost two pages of disadvantages! The disadvantages use up only three paragraphs as well.

Finally, an interesting mistake was pointed out to me by Chris Main. It appears that a bug in the SGI MipsPro C++ compiler allows the compiler to pick the intended getCoord() function template even though, according to the Standard, it should not be able to. This is worth expanding upon. Let me recall the summary here:

I showed how a processor (object or function) that uses data from a set of objects of a certain type can be generalized with a very small number of lines of code, using templates and specializations, such that the processor doesn't need to be changed when the data structure changes. More specifically, your processor object or function is able to extract the needed data from the container elements, regardless of whether the container element type

  1. Is the data, or is a pointer to the data (as opposed to containing it)

  2. Is an object or a pointer to an object, containing the data

  3. Makes data available as attribute OR method (which we don't address in this addendum)

Finally, the compiler does this for you automatically, without requiring your intervention.

Two of the functions and templates used were:

/// General function template
template <class P> inline
const Coord& getCoord(const P& p) {
  return p.coords;
}

/// Overload for pointers to things
template <class P>
const Coord& getCoord(const P* p) {
  return p->coords;
}

where P is one of the six types of data described in 1-3 above. As Chris pointed out to me, given the code fragment

Struct Point {Coord coord;};
Point coord;
getCoord(&coord);

the compiler has two choices for getCoord():

  1. getCoord<Point*>(const Point*&)

  2. getCoord<Point>(const Point*)

Which one will the compiler choose? The one we want (#2) or #1? With SGI's mipspro compiler, it chooses #2. With gcc 2.95, it chooses #1. I thought it was a bug with gcc but Chris gives good evidence that it is the other way around: overload resolution states that the compiler must choose the most "specific" template, which is #1, since the parameter is a pointer to the type rather than just the type.

This could seem like a major problem for the techniques discussed in that article but really it isn't because the concepts used were sound, it's just the technique used to implement them that got side-tracked onto a wrong path. The fundamental problem is how to tell the compiler to deal with two separate cases of data, one a type, the other a pointer to a type (a "pointer type"). This is easy with partial specialization of a class that does nothing for types, and does a dereference for a pointer type:

template <typename P>
struct Obj {
  static const P& getObj(const P& p) {
    return p;
  }
};
// partial specialization for pointer
// types
template <typename P>
struct Obj<P*> {
  static const P& getObj(const P* p) {
    return *p;
  }
};

They replace two of the four getCoord() overloads mentioned in the article, namely the ones with pointer types as parameter, and are used by calling

getCoord( Obj<T>::getObj(p) )

instead of

getCoord(p)

In any case, I hope you found the article interesting and maybe even useful. Thanks to Alan and Chris for sending feedback. As usual, I find that writing articles is fun and challenging, but I inevitably seem to learn a lot more than I could have expected from the feedback of readers. I encourage you to give it a try, write an article for Overload!

References

[Stroustrup] Bjarne Stroustrup, C++ Programming Language, 3rd ed.

[Alexandrescu] Andrei Alexandrescu, Modern C++ Design

[Schoenborn] Oliver Schoenborn, "Tiny Template Tidbit," Overload 47

Overload Journal #54 - Apr 2003 + Programming Topics