13.4 String Literal and Floating-Point Template Arguments

Ru-Brd

Among the restrictions on nontype template arguments, perhaps the most surprising to beginning and advanced template writers alike is the inability to provide a string literal as a template argument.

The following example seems intuitive enough:

 template <char const* msg>  class Diagnoser {    public:      void print();  };  int main()  {      Diagnoser<"Surprise!">().print();  } 

However, there are some potential problems. In standard C++, two instances of Diagnoser are the same type if and only if they have the same arguments. In this case the argument is a pointer value ”in other words, an address. However, two identical string literals appearing in different source locations are not required to have the same address. We could thus find ourselves in the awkward situation that Diagnoser<"X"> and Diagnoser<"X"> are in fact two different and incompatible types! (Note that the type of "X" is char const[2] , but it decays to char const* when passed as a template argument.)

Because of these (and related ) considerations, the C++ standard prohibits string literals as arguments to templates. However, some implementations do offer the facility as an extension. They enable this by using the actual string literal contents in the internal representation of the template instance. Although this is clearly feasible , some C++ language commentators feel that a nontype template parameter that can be substituted by a string literal value should be declared differently from one that can be substituted by an address. At the time of this writing, however, no such declaration syntax has received overwhelming support.

We should also note an additional technical wrinkle in this issue. Consider the following template declarations, and let's assume that the language has been extended to accept string literals as template arguments in this case:

 template <char const* str>  class Bracket {    public:      static char const* address() const;      static char const* bytes() const;  };  template <char const* str>  char const* Bracket<T>::address() const  {      return str;  }  template <char const* str>  char const* Bracket<T>::bytes() const  {      return str;  } 

In the previous code, the two member functions are identical except for their names ”a situation that is not that uncommon. Imagine that an implementation would instantiate Bracket<"X"> using a process much like macro expansion: In this case, if the two member functions are instantiated in different translation units, they may return different values. Interestingly, a test of some C++ compilers that currently provide this extension reveals that they do suffer from this surprising behavior.

A related issue is the ability to provide floating-point literals (and simple constant floating-point expressions) as template arguments. For example:

 template <double Ratio>  class Converter {    public:      static double convert (double val) const {          return val*Ratio;      }  };  typedef Converter<0.0254> InchToMeter; 

This too is provided by some C++ implementations and presents no serious technical challenges (unlike the string literal arguments).

Ru-Brd


C++ Templates
C++ Templates: The Complete Guide
ISBN: 0201734842
EAN: 2147483647
Year: 2002
Pages: 185

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net