Global function template overloading and const parameters - c++

If I compile (gcc 4.6.0) and run this code:
#include <iostream>
template <typename T> void F(/* const */ T& value) {
std::cout << "T & " << value << std::endl;
}
template <typename T> void F(/* const */ T* value) {
std::cout << "T * " << value << std::endl;
F(*value);
}
int main(int argc, char* argv[]) {
float f = 123.456;
float* pf = &f;
F(pf);
return 0;
}
I get the following output:
T * 0x7fff7b2652c4
T & 123.456
If I uncomment the const keywords I get the following output:
T & 0x7fff3162c68c
I can change float* pf = &f; to const float* pf = &f; to get the original output again, that's not the issue.
What I'd like to understand is why, when compiling with the const modifiers, overload resolution considers const T& value a better match than const T* valuefor a non-const float*?

During overload resolution, overloads requiring no conversions beat overloads requiring some conversions, even if those conversions are trivial. Quoting the C++03 standard, [over.match.best] (§13.3.3/1):
Define ICSi(F) as follows:
if F is a static member function, ICS1(F) is defined such that ICS1(F) is neither better nor worse than ICS1(G) for any function G, and, symmetrically, ICS1(G) is neither better nor worse than ICS1(F); otherwise,
let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
F1 is a non-template function and F2 is a function template specialization, or, if not that,
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.5.2, or, if not that,
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.
When const is present, in order to call the overload taking a reference, no conversion is necessary -- T is deduced to be float* and the argument is float* const&. However, in order to call the overload taking a pointer, float would need to be converted to float const for said overload to be viable. Consequently, the overload taking a reference wins.
Note, of course, that if pf were changed to be a float const*, the behavior would go back to the way you expected because the overload taking a pointer would no longer require a conversion.

Related

Understand the whole process of function template overload resolution

I found out that the overload resolution process is the more complicated I have ever learned in C++, Therefore, bear in mind that this topic is relatively difficult for me to understand easily, so be patient with me.
I have two examples here, and I tried to parse each example separately and understand what actually the compiler is doing starting from the call to the overloaded template until determining which overload is the best viable.
First Example #1
template <class T> void f(const T&); // F1: reference to const T
template <class T> void f(const T*); // F2: pointer to const T
f((int*)0);
// matching F1:
// deduction: P = const T&, A = int* --> const T& = int* --> T = int*
// instantiates: void f(int *const&); A = int*, P = int *const&
// S1 conversion: int* --> int* const& (identity conversion?)
// matching F2:
// P = const T*, A = int* --> const T* = int*; T = int;
// instantaies: void f(const int*); A = int*, P = const int*;
// S2 conversion: int* --> const int* (qualification conversion)
Per [over.ics.rank]/3/3.2
Standard conversion sequence S1 is a better conversion sequence than
standard conversion sequence S2 if
(3.2.1) S1 is a proper subsequence
of S2 (comparing the conversion sequences in the canonical form
defined by 12.2.4.2.2, excluding any Lvalue Transformation; the
identity conversion sequence is considered to be a subsequence of any
non-identity conversion sequence)
[..]
S1 is s a proper subsequence of S2: that's identity conversion is a proper subsequence of qualification conversion because the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence.
and per [over.match.best.general]/2:
Given these definitions, a viable function F1 is defined to be a
better function than another viable function F2 if for all arguments
i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
(2.1) — for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2)
[..]
Here, the implicit conversions for all arguments of F1 (which is identity conversion) are "not worse" than the implicit conversions for all arguments of F2 (which is qualification conversion), and there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2. Then the viable function F1 is a better function than the viable function F2. Hence, a specialization of F1 gets chosen by the overload resolution for the given call.
My questions:
Have I parsed the whole process correctly?
Does the compiler need to perform partial ordering at this point? if yes, why?, even though we knowfrom ICS that F1 is the best viable candidate?
Second Example #2
template <class T> void f(const T&); // F1: reference to const T
template <class T> void f(T*); // F2: pointer to T
f((int*)0);
// matching F1:
// deduction: P = const T&, A = int* --> const T& = int* --> T = int*
// instantiates: void f(int *const&); A = int*, P = int *const&
// S1 conversion: int* --> int* const& (identity conversion)
// matching F2:
// deduction: P = T*, A = int* --> T* = int*; T = int
// instantaies: void f(int*); A = int*, P = int*
// S2 conversion: int* --> int* (identity conversion)
Here neither rule in [over.ics.rank]/3/3.2 is applied; that's both S1 and S2 are identity conversions.
Then the compiler goes to the next step to check the rules defined in [over.match.best.general]/2. Indeed ICSi(F1) is not a worse conversion sequence than ICSi(F2), but the 2.1 bullet is not satisfied because ICSi(F1) is not a better conversion sequence than ICSi(F2). The implicit conversion sequence for the argument of F1 is actually the same (i.e not worse) as that of F2.
The compiler keeps checking the rules in [over.match.best.general]/2 until it hits bullet 2.5 which says:
[..]
(2.5) — F1 and F2 are function template specializations and the
function template for F1 is more specialized than the template for F2
according to the partial ordering rules [..]
I am not going through the whole process of partial ordering, instead, I will summarize things as possible.
Adjustment Function Signature:
void f(T); // Tem1
void f(T*); // Tem2
Transformed Function Signature:
void f(U1); // Tra1
void f(U2*); // Tra2
Matching Tem1 against Tran2:
void f(T); // Tem1
void f(U2*); // Tra2
// T = U2* - OK: T can be deduced from U2*
Matching Tem2 against Tran1:
void f(T*); // Tem2
void f(U1); // Tra1
// T* = U1 - error: T cannot be deduced
So template referred by Tra2 is more specialized than the template referred by Tran1: F2 is more specialized than F1. Therefore a specialization of F2 will be selected by the overload resolution for the given call.
My questions:
Have I parsed the whole process correctly?
What I think (it might be incorrect) is that after template argument deduction, the compiler generates specializations for both overloads to match P/A pairs for the ICS process. Now does the compiler generates a specialization again for the more-specialized template?
Believe me, before posting this question, I searched a lot for a question that covers that whole process. What I need to know, Am I thinking right, and whether all quotes I provided are applied to the examples or not.
Sorry for taking long, and Thanks in advance.

Overload resolution, templates and inheritance

#include <iostream>
struct A {};
struct B : public A {};
template<typename T>
void foo(const T &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
int main()
{
foo(A());
foo(B());
return 0;
}
This prints:
Called A
Called template
I was under the impression that a suitable non-template function would always be chosen over a template function. Can someone explain to me the resolution steps that lead to this somewhat surprising result?
I was under the impression that a suitable non-template function would always be chosen over a template function.
This only holds if the template and the non-template are equally good candidates. That's why the non-template is chosen for foo(A()).
However, in the case of foo(B()), using the non-template requires a derived-to-base conversion. So the function template is strictly better, and hence it's chosen.
The foo template instantiates into void foo(const B&). Consider what it would look like without templates:
void foo(const B &x) { std::cout << "Called template" << std::endl; }
void foo(const A &a) { std::cout << "Called A" << std::endl; }
I believe you'll agree calling foo(B()) should unambiguously pick the first one. That's exactly why the template is chosen.
n3376 13.3.3.1/6
When the parameter has a class type and the argument expression has a
derived class type, the implicit conversion sequence is a
derived-to-base Conversion from the derived class to the base class.
n3376 13.3.3.1/8
If no conversions are required to match an argument to a parameter
type, the implicit conversion sequence is the standard conversion
sequence consisting of the identity conversion (13.3.3.1.1).
Identity conversion has exact match rank due table in 13.3.3.1.1/table 12, but derived-to-base is worse, than identity.
So, compiler just have candidates in first case
// template after resolving
void foo(const A&)
// non-template
void foo(const A&)
Both has identity rank, but since first is function-template, second will be chosen.
And in second case
// template after resolving
void foo(const B&)
// non-template
void foo(const A&)
Only first has identity rank and will be chosen.
Can someone explain to me the resolution steps that lead to this somewhat surprising result?
you may look at Overload Resolution at cppreference.com:
http://en.cppreference.com/w/cpp/language/overload_resolution
in particular see the section Ranking of implicit conversion sequences
Extension of the Answer:
I tried to provide more clarification with an excerpt of the information from the aforementioned link:
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
For that, the compiler goes through:
function template name lookup
template argument deduction
Down to here, the compiler has a couple of candidate function definitions which can handle the specific function call. These candidates are instannces of the template function as well as relevant non-template function definitions in the program.
But the answer to your question lies in fact here:
Template argument deduction takes place after the function template name lookup (which may involve argument-dependent lookup) and before overload resolution.
The fact that function overload resolution is performed after template function instantiation is the reason for the ouput of your code.
Now your specific case goes through overload resolution as the following:
Overload Resolution:
If the [previous] steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called. In general, the candidate function whose parameters match the arguments most closely is the one that is called.
.
.
.
...
F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and
1) there is at least one argument of F1 whose implicit conversion is better than the corresponding implicit conversion for that argument of F2
...
.
.
.
Ranking of implicit conversion sequences:
Each type of standard conversion sequence is assigned one of three ranks:
1) Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, user-defined conversion of class type to the same class
2) Promotion: integral promotion, floating-point promotion
3) Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
The rank of the standard conversion sequence is the worst of the ranks of the standard conversions it holds (there may be up to three conversions)
Binding of a reference parameter directly to the argument expression is either Identity or a derived-to-base Conversion:
struct Base {};
struct Derived : Base {} d;
int f(Base&); // overload #1
int f(Derived&); // overload #2
int i = f(d); // d -> Derived& has rank Exact Match
// d -> Base& has rank Conversion
// calls f(Derived&)

Function Matching for parameters of type const T& and T

I have a question regarding the c++ function matching for parameters of types T and const T&.
Let's say I have the following two functions:
void f(int i) {}
void f(const int &ri) {}
If I call f with an argument of type const int then this call is of course ambiguous. But why is a call of f with an argument of type int also ambiguous? Wouldn't be the first version of f be an exact match and the second one a worse match, because the int argument must be converted to a const int?
const int ci = 0;
int i = 0;
f(ci); // of course ambiguous
f(i); // why also ambiguous?
I know that such kind of overloading doesn't make much sense, because calls of f are almost always ambiguous unless the parameter type T doesn't have an accessible copy constructor. But I'm just studying the rules of function matching.
Regards,
Kevin
EDIT: To make my question more clear. If I have the two functions:
void f(int *pi) {}
void f(const int *pi) {}
Then the following call is not ambiguous:
int i = 0;
f(&i); // not ambiguous, first version f(int*) chosen
Although both versions of f could be called with &i the first version is chosen, because the second version of f would include a conversion to const. That is, the first version is a "better match". But in the two functions:
void f(int i) {} and
void f(const int &ri) {}
This additional conversion to const seems to be ignored for some reason. Again both versions of f could be called with an int. But again, the second version of f would require a conversion to const which would make it a worse match than the first version f(int).
int i = 1;
// f(int) requires no conversion
// f(const int &) does require a const conversion
// so why are both versions treated as "equally good" matches?
// isnt this analogous to the f(int*) and f(const int*) example?
f(i); // why ambiguous this time?
One call involves an "lvalue-to-rvalue conversion", the other requires an identity conversion (for references) or a "qualification adjustment" (for pointers), and according to the Standard these are treated equally when it comes to overload resolution.
So, neither is better on the basis of differing conversions.
There is, however, a special rule in the Standard, section 13.3.3.2, that applies only if both candidates being compared take the parameter by reference.
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if ... S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
There's an identical rule for pointers.
Therefore the compiler will prefer
f(int*);
f(int&);
over
f(const int*);
f(const int&);
respectively, but there's no preference for f(int) vs f(const int) vs f(const int&), because lvalue-to-rvalue transformation and qualification adjustment are both considered "Exact Match".
Also relevant, from section 13.3.3.1.4:
When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion.
The second call f(i) is also ambiguous because void f(const int &ri) indicates that ri is a reference to i and is a constant. Meaning it says that it will not modify the original i which is passed to that function.
The choice whether to modify the passed argument or not is in the hands of the implementer of the function not the client programmer who mearly uses that function.
The reason the second call f(i) is ambiguous is because to the compiler, both functions would be acceptable. const-ness can't be used to overload functions because different const versions of functions can be used in a single cause. So in your example:
int i = 0;
fi(i);
How would the compiler know which function you intended in invoking? The const qualifier is only relevant to the function definition.
See const function overloading for a more detailed explanation.

Why does this code call different template function in vs2005?

The code is:
#include <iostream>
using namespace std;
// compares two objects
template <typename T> void compare(const T&, const T&){
cout<<"T"<<endl;
};
// compares elements in two sequences
template <class U, class V> void compare(U, U, V){
cout<<"UV"<<endl;
};
// plain functions to handle C-style character strings
void compare(const char*, const char*){
cout<<"ordinary"<<endl;
};
int main() {
cout<<"-------------------------char* --------------------------"<< endl;
char* c="a";
char* d="b";
compare(c,d);
cout<<"------------------------- char [2]---------------------------"<< endl;
char e[]= "a";
char f[]="b";
compare(e,f);
system("pause");
}
The result is:
-------------------------char* --------------------------
T
------------------------- char [2]-----------------------
ordinary
And my question is:
Why does compare(c,d) call compare(const T&, const T&) and compare(e,f) call the ordinary function even though the arguments of the two functions are char*s?
It appears that VS2005 may be erroneously treating the e and f variables as const char * types.
Consider the following code:
#include <iostream>
using namespace std;
template <typename T> void compare (const T&, const T&) {
cout << "T: ";
};
template <class U, class V> void compare (U, U, V) {
cout << "UV: ";
};
void compare (const char*, const char*) {
cout << "ordinary: ";
};
int main (void) {
char* c = "a";
char* d = "b";
compare (c,d);
cout << "<- char *\n";
char e[] = "a";
char f[] = "b";
compare (e,f);
cout << "<- char []\n";
const char g[] = "a";
const char h[] = "b";
compare (g,h);
cout << "<- const char []\n";
return 0;
}
which outputs:
T: <- char *
T: <- char []
ordinary: <- const char []
Section 13.3 Overload resolution of C++03 (section numbers appear to be unchanged in C++11 so the same comments apply there) specifies how to select which function is used and I'll try to explain it in (relatively) simple terms, given that the standard is rather a dry read.
Basically, a list of candidate functions is built based on how the function is actually being called (as a member function of an class/object, regular (unadorned) function calls, calls via a pointer and so on).
Then, out of those, a list of viable functions is extracted based on argument counts.
Then, from the viable functions, the best fit function is selected based on the idea of a minimal implicit conversion sequence (see 13.3.3 Best viable function of C++03).
In essence, there is a "cost" for selecting a function from the viable list that is set based on the implicit conversions required for each argument. The cost of selecting the function is the sum of the costs for each individual argument to that function, and the compiler will chose the function with the minimal cost.
If two functions are found with the same cost, the standard states the the compiler should treat it as an error.
So, if you have a function where an implicit conversion happens to one argument, it will be preferred over one where two arguments have to be converted in that same way.
The "cost" can be see in the table below in the Rank column. An exact match has less cost than promotion, which has less cost than conversion.
Rank Conversion
---- ----------
Exact match No conversions required
Lvalue-to-rvalue conversion
Array-to-pointer conversion
Function-to-pointer conversion
Qualification conversion
Promotion Integral promotions
Floating point promotions
Conversion Integral conversion
Floating point conversions
Floating-integral conversions
Pointer conversions
Pointer-to-member conversions
Boolean conversions
In places where the conversion cost is identical for functions F1 and F2 (such as in your case), F1 is considered better if:
F1 is a non-template function and F2 is a function template specialization.
However, that's not the whole story since the template code and non-template code are all exact matches hence you would expect to see the non-template function called in all cases rather than just the third.
That's covered further on in the standard: The answer lies in section 13.3.3.2 Ranking implicit conversion sequences. That section states that an identical rank would result in ambiguity except under certain conditions, one of which is:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if (1) 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) ...
The conversions for the template version are actually a proper subset (qualification conversion) of the non-template version (qualification AND array-to-pointer conversions), and proper subsets are deemed to have a lower cost.
Hence it prefers the template version in the first two cases. In the third case, the only conversions are array-to-pointer for the non-template version and qualification for the template version, hence there's no subset in either direction, and it prefers the non-template version based on the rule I mentioned above, under the ranking table).

What are the rules for choosing from overloaded template functions?

Given the code below, why is the foo(T*) function selected ?
If I remove it (the foo(T*)) the code still compiles and works correctly, but G++ v4.4.0 (and probably other compilers as well) will generate two foo() functions: one for char[4] and one for char[7].
#include <iostream>
using namespace std;
template< typename T >
void foo( const T& )
{
cout << "foo(const T&)" << endl;
}
template< typename T >
void foo( T* )
{
cout << "foo(T*)" << endl;
}
int main()
{
foo( "bar" );
foo( "foobar" );
return 0;
}
Formally, when comparing conversion sequences, lvalue transformations are ignored. Conversions are grouped into several categories, like qualification adjustment (T* -> T const*), lvalue transformation (int[N] -> int*, void() -> void(*)()), and others.
The only difference between your two candidates is an lvalue transformation. String literals are arrays that convert to pointers. The first candidate accepts the array by reference, and thus won't need an lvalue transformation. The second candidate requires an lvalue transformation.
So, if there are two candidates that both function template specializations are equally viable by looking only at the conversions, then the rule is that the more specialized one is chosen by doing partial ordering of the two.
Let's compare the two by looking at their signature of their function parameter list
void(T const&);
void(T*);
If we choose some unique type Q for the first parameter list and try to match against the second parameter list, we are matching Q against T*. This will fail, since Q is not a pointer. Thus, the second is at least as specialized as the first.
If we do the other way around, we match Q* against T const&. The reference is dropped and toplevel qualifiers are ignored, and the remaining T becomes Q*. This is an exact match for the purpose of partial ordering, and thus deduction of the transformed parameter list of the second against the first candidate succeeds. Since the other direction (against the second) didn't succeed, the second candidate is more specialized than the first - and in consequence, overload resolution will prefer the second, if there would otherwise be an ambiguity.
At 13.3.3.2/3:
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 [...]
Then 13.3.3/1
let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then [...]
F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.5.2, or, if not that, [...]
Finally, here is the table of implicit conversions that may participate in an standard conversion sequence at 13.3.3.1.1/3.
Conversion sequences http://img259.imageshack.us/img259/851/convs.png
The full answer is quite technical.
First, string literals have char const[N] type.
Then there is an implicit conversion from char const[N] to char const*.
So both your template function match, one using reference binding, one using the implicit conversion. When they are alone, both your template functions are able to handle the calls, but when they are both present, we have to explain why the second foo (instantiated with T=char const[N]) is a better match than the first (instantiated with T=char). If you look at the overloading rules (as given by litb), the choice between
void foo(char const (&x)[4));
and
void foo(char const* x);
is ambigous (the rules are quite complicated but you can check by writing non template functions with such signatures and see that the compiler complains). In that case, the choice is made to the second one because that one is more specialized (again the rules for this partial ordering are complicated, but in this case it is because you can pass a char const[N] to a char const* but not a char const* to a char const[N] in the same way as void bar(char const*) is more specialized than void bar(char*) because you can pass a char* to a char const* but not vise-versa).
Based on overload resolution rules (Appendix B of C++ Templates: The Complete Guide has a good overview), string literals (const char []) are closer to T* than T&, because the compiler makes no distinction between char[] and char*, so T* is the closest match (const T* would be an exact match).
In fact, if you could add:
template<typename T>
void foo(const T[] a)
(which you can't), your compiler would tell you that this function is a redefinition of:
template<typename T>
void foo(const T* a)
Cause " " is a char*, which fits perfectly to foo(T*) function. When you remove this, the compiler will try to make it work with foo(T&), which requires you to pass reference to char array that contains the string.
Compiler can't generate one function that would receive reference to char, as you are passing whole array, so it has to dereference it.