Friday, January 17, 2014

passing string literals as function template parameter

passing string literals as function template parameter c++ : templates tutorial
Passing string literal arguments for reference parameters of function templates sometimes fails in a surprising way. Consider the following example:

The problem is that string literals have different array types depending on their lengths. That is, "apple" and "peach" have type char const[6] whereas "tomato" has type char const[7]. Only the first call is possible because the template expects both parameters to have the same type. However, if you declare nonreference parameters, you can substitute them with string literals of different size:

The explanation for this behavior is that during argument deduction array-to-pointer conversion (often called decay) occurs only if the parameter does not have a reference type. This is demonstrated by the following program:

The example passes a string literal to function templates that declare their parameter to be a reference or nonreference respectively. Both function templates use the typeid operator to print the type of the instantiated parameters. The typeid operator returns an lvalue of type std::type_info, which encapsulates a representation of the type of the expression passed to the typeid operator. The member function name() of std::type_info is intended to return a human-readable text representation of the latter type. The C++ standard doesn't actually say that name() must return something meaningful, but on good C++ implementations, you should get a string that gives a good description of the type of the expression passed to typeid (with some implementations this string is mangled, but a demangler is available to turn it into human-readable text). For example, the output might be as follows:

If you encounter a problem involving a mismatch between an array of characters and a pointer to characters, you might have stumbled on this somewhat surprising phenomenon. There is unfortunately no general solutions to address this problem. Depending on the context, you can
In fact, this is the reason that you cannot create a pair of values initialized with string literals using the original C++ standard library:

This was fixed with the first technical corrigendum by replacing the reference parameters of make_pair() by nonreference parameters.
  • use nonreferences instead of references (however, this can lead to unnecessary copying)
  • overload using both reference and nonreference parameters (however, this might lead to ambiguities;)
  • overload with concrete types (such as std::string)
  • overload with array types, for example:

  • force application programmers to use explicit conversions

In this example it is best to overload max() for strings. This is necessary anyway because without overloading in cases where the call to max() is valid for string literals, the operation that is performed is a pointer comparison: a<bcompares the addresses of the two string literals and has nothing to do with lexicographical order. This is another reason why it is usually preferable to use a string class such as std::string instead of C-style strings.

See Also:


No comments:

Post a Comment