views:

58

answers:

2

I have two functions :

void foo(const char * p)

and

template<size_t T_Size>
void foo(const char (& p)[T_Size]) ;

Given the call:

int main(int argc, char* argv[])
{
   char a[21] ;                          // typeid : A21_c
   sprintf(a, "a[21] : Hello World") ;

   const char * b = "b : Hello World" ;  // typeid : PKc

   // note that literal "liter. : Hello World" has a typeid : A21_c

   foo(a) ;                      // calls foo(const char (& p)[T_Size])
   foo(b) ;                      // calls foo(const char * p)
   foo("liter. : Hello World") ; // calls foo(const char * p) ???

   return 0 ;
}

Apparently, calling foo with a stack-based correctly declared array behaves as expected, while calling foo with a literal "liter. : Hello World" does not, despite the two having the same type (according to RTTI).

What are exactly the rules followed by the ADL (a.k.a the Koenig's Lookup) to choose one overload over the other ?

Why the different behaviour between a declared array and a string literal ?

Thanks !

Edit

Note that a way to have the desired result (i.e. have a litteral string match the foo(const char (& p)[T_Size]) function) is to remove the void foo(const char *p) and add instead:

struct FooIndirect
{
    const char * m_p ;
    FooIndirect(const char *p) : m_p(p) {}
} ;

void foo(const FooIndirect & p)
{
    // do something with p.m_p
}

This indirection makes the templated foo a better match for string litterals, and still enables the user to use pointers (the indirection will be removed in optimized compilation mode).

I tested it on my g++ 4.4.3, but I believe it will work the same way on every compiler.

+1  A: 

The compiler will always call non-templated overloads if available in comparison to templated functions. You provided a perfectly adequate non-templated overload, so the compiler calls it.

DeadMG
+1 because your reason is perfectly valid.
Prasoon Saurav
So why is the non-template overload not "perfectly adequate" for a non-const array? Too many conversions required?
Steve Jessop
@Steve: For this case, there are two conversions required: Array to pointer conversion (Exact Match) ---> qualification adjustment. For template overload, this is an exact match As per $13.3.3.2/3, the sequence for non-template overload is a proper subsequence of the sequences required for template overload, and is therefore preferred.
Chubsdad
I see. So turn the pointer version of foo into a template which only successfully instantiates for `const char*` (and things convertible to that), and you're done.
Steve Jessop
+4  A: 

Table 9 in Chapter 13(Overload Resolution) of the Standards, ranks "Array to pointer" conversion (for non-template) to be of the same rank (EXACT MATCH) as "no Conversion Required" (for the template version).

Everything else being the same, the non-template version is preferred over the template version.

Chubsdad
Note: Qualification adjustments have Exact Match rank too, yet they can make one function be preferred over another. The better reason they are equal is because of 13.3.3.2/3, which says "Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if ... S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by 13.3.3.1.1, *excluding any Lvalue Transformation;* the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence) or, if not that ..."
Johannes Schaub - litb