tags:

views:

115

answers:

3

I have template function "compare" defined as below.

#include<iostream>
using namespace std;

template<typename T>
void compare(const T&a, const T& b)
{
    cout<<"Inside compare"<<endl;
}

main()
{
compare("aa","bb");
compare("aa","bbbb");
}

When i instantiate compare with string literals of same length, the compiler doesnot complain. When i do it with literals of different length,it says "error: no matching function for call to compare(const char[3],const char[5])"

I am confused as compare function should be instantiated with character pointer rather than character array. Should not string literals always decay to pointer?

+6  A: 

Your example compiles if you change the declaration to:

void compare(const T* a, const T* b)

The reason is that the types of the different sized character arrays are actually different types. If you used sizeof(T) within the template function the compiler would not know how to resolve the ambiguity. With the above declaration, you are calling a template function with pointer-to-T types, which the compiler will happily resolve as const char* when passed character strings.

Greg Hewgill
@Greg, what is the problem with the current declaration?
chappar
Your declaration as written requires that the function compare takes two parameters that are exactly the same type. "const char[3]" and "const char[5]" are not the same type.
Greg Hewgill
In your existing code, the "compare" would evaluate to something like void compare( char a[2], char b[4] ). Using pointers instead of references means T can be safely evaluated a "char", instead of two differently sized arrays (which are different types).
Justicle
chappar
@chappar: Your understanding is incorrect. Arrays are types too (they aren't just pointers) and literal strings are interpreted by the compiler as arrays of characters (instead of pointers to characters).
Greg Hewgill
+3  A: 

The compiler will prefer to interpret string literals as character buffers if it can. If not, it can interpret them as const char *. However, the compiler isn't going to do any backtracking to try to find the best interpretation of T. It's not that complicated. Once it decides that T is a const char[3], it moves on. Evaluating the second argument then fails.

If you call it with

compare(static_cast<const char *>("aa"),static_cast<const char *>("bbbb"));

You're good to go.

Drew Hoskins
but it reads like hell :)
xtofl
compare<char const*>("aa", "bbbb"), and templates + overload resolution isn't nearly that simple :(
Roger Pate
Template overload resolution isn't simple, agreed, but it isn't complex enough to infer a type for T that unifies both variables here, even though you could imagine an implementation that would.
Drew Hoskins
+4  A: 

As stated in Greg's answer and comments, the two different array types (since that's what string literals are) is the problem. You may want to leave the function as-is for generic types, but overload it for character pointers and arrays, this is mostly useful when you want to treat them slightly differently.

void compare(char const* a, char const* b) {
    // do something, possibly use strlen()
}

template<int N1, int N2>
void compare(char const (&a)[N1], char const (&b)[N2]) {
    // ...
}

If you want to specify that compare should take character pointers explicitly, then the arrays will automatically convert:

compare<char const*>("aa", "bbbb");

On the other hand, maybe compare could be written to work with two different types? This can be useful for other types as well, e.g. maybe it calls f(a) if a.size() < b.size(), and f(b) otherwise (with f overloaded). (T1 and T2 are allowed to be the same type below, and this would replace your function instead of overloading it as the above two.)

template<typename T1, typename T2>
void compare(T1 const& a, T2 const& b) {
    // ...
}
Roger Pate