Consider this piece of C++11 code:
#include <iostream>
#include <cstddef>
template<typename T> void f(T, const char*) //#1
{
std::cout << "f(T, const char*)\n";
}
template<std::size_t N> void f(int, const char(&)[N]) //#2
{
std::cout << "f(int, const char (&)[N])\n";
}
int main()
{
f(7, "ab");
}
Alright, so... which overload is chosen? Before spilling the beans with compiler output, let's try to reason about this.
(All references to sections are for the final standard document for C++11, ISO/IEC 14882:2011.)
T from #1 is deduced to int, N from #2 is deduced to 3, both overloads are candidates, both are viable, so far so good. Which one is best?
First, the implicit conversions needed to match function arguments with function parameters are considered. For the first argument, no conversion is needed in either case (identity conversion), int everywhere, so the two functions are equally good. For the second one, the argument type is const char[3], and the two conversions are:
- for #1, array-to-pointer conversion, category lvalue transformation, according to
[13.3.3.1.1]; this conversion category is ignored when comparing conversion sequences according to[13.3.3.2], so this is basically the same as identity conversion for this purpose; - for #2, the parameter is of reference type and binds directly to the argument, so, according to
[13.3.3.1.4], this is again identity conversion.
Again, no luck: the two functions are still equally good. Both being template specializations, we now have to see which function template, if any, is more specialized ([14.5.6.2] and [14.8.2.4]).
- Template argument deduction with #1 as parameter and #2 as argument: we invent a value
Mto substitute forN,Tdeduced asint,const char*as parameter can bind toconst char(&)[M], everything's fine. As far as I can tell, #2 is at least as specialized as #1 for all types involved. - Template argument deduction with #2 as parameter and #1 as argument: we invent a type
Uto substitute forT,intcannot bind toU(unrelated types), a parameter of typeconst char (&)[N]cannot bind toconst char*, moreover, the value of the non-type parameterNcannot be deduced from the arguments, so... everything fails. As far as I can tell, #1 is not at least as specialized as #2 for all types involved.
Based on the above, I'd say partial ordering of function templates should choose #2 as more specialized, and the call should resolve to it with no ambiguity.
Now, back to the harsh reality. Both GCC 4.9.1 and Clang 3.5.0, with the following options
-Wall -Wextra -std=c++11 -pedantic
reject the call as ambiguous, with similar error messages. The error from Clang is:
prog.cc:16:2: error: call to 'f' is ambiguous
f(7, "ab");
^
prog.cc:4:27: note: candidate function [with T = int]
template<typename T> void f(T, const char*) //#1
^
prog.cc:9:30: note: candidate function [with N = 3]
template<std::size_t N> void f(int, const char(&)[N]) //#2
^
Visual C++ 2013's IntelliSense (based on the EDG compiler, as far as I know) also flags the call as ambiguous. Funnily enough, the VC++ compiler goes ahead and compiles the code with no errors, choosing #2. (Yay! It agrees with me, so it must be right.)
The obvious question for the experts is, why is the call ambiguous? What am I missing (in the partial ordering area, I would guess)?
Aucun commentaire:
Enregistrer un commentaire