Non-const pointer prefers const T& overload to const T* - c++

Suppose I have two overloads of a function
template <typename T>
void f(const T&) {
cout << "f(T&)" << endl;
}
template <typename T>
void f(const T*) {
cout << "f(T*)" << endl;
}
Why does f(new int) resolves to the f(const T&) instead of f(const T*)? Anywhere in the standard talks about this counter-intuitive behavior?
http://ideone.com/kl8NxL

For overload resolution with template deduction, the first step is to resolve the templates. Then non-template ordering is applied to the results. In your code the template resolutions are:
void f(int * const &) // 1
void f(int const *) // 2
According to C++14 [over.ics.ref], a reference binding directly to an argument as in (1) is an identity conversion (even if there are added cv-qualifiers). The binding of T to T const & is a direct binding, i.e. no temporaries are created and bound.
However, (2) involves a qualification conversion. The argument type int * must be converted to const int * before it matches the function parameter.
The identity conversion is considered a sub-sequence of any non-identity conversion sequence, so (1) wins according to the sub-sequence rule [over.ics.rank]/3.1.1

Related

Why is this template expansion legal in C++?

Consider the following code:
template <typename T>
void foo(const T& param) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
std::cout << param;
}
int main()
{
foo<const int&>(5);
return 0;
}
The output gives:
void foo(const T&) [with T = const int&]
5
Here apparently T is resolved to const int& (as the printout says, since I explicitly forced so). However, this seems to create a problem: The function signature takes a parameter of type const T&, and in this case it would expand to const const int& &, which is not legal syntax in C++.
But the program indeed runs fine. What's going on here?
Update:
I know that T& & would collapse to T&. However, in this case, the double const is also not legal if you write them explicitly, and I don't see that template collapsing rule mention this part.
Update 2:
Compiling const const int x = 1; gives error: duplicate ‘const’. Multiple const is not allowed in c++ (but surprisingly in c it's okay).
C++ types are not formed by textual replacement. const T& where T is void * is void* const &, not const void *&.
Your code attempts to form the type "lvalue reference to const T" where T is "lvalue reference to const int". By the reference collapsing rules, that will instead form the type "lvalue reference to const int".

Function template overload resolution using const references

I am trying to understand the overload resolution rules in the following case:
template<typename T>
void f(const T& x) {
std::cout << __PRETTY_FUNCTION__ << std::endl; //-
}
template<typename T>
void f(T& x) { // <> Überladung Variante 2
std::cout << __PRETTY_FUNCTION__ << std::endl; //-
}
int main()
{
int e1 = 0;
f(e1);
const int e2 = 0;
f(e2);
}
The output is:
void f(T &) [T = int]
void f(const T &) [T = int]
As I understand in the first call to f(e1) leads to the viable functions
void f(const int&)
void f(int&)
from which the first one is chosen because the const-qualification hasn't to be removed.
The second call to f(e2) leads to the type deductions / viable functions
void f(const int&); // T -> int from first template overload
void f(const int&); // T -> const int from second overload
and the output shows that the first overload is choosen.
But why?
When performing type deduction with references, the const-ness (more specifically CV-ness) is not removed. So in your case the compiler has 2 overloads to choose from:
void f(const T &)
void f(T &)
The compiler then performs "pattern matching" when choosing the overload for your const int e2 = 0; argument. The first const overload is a better match (more specialized), as the second one would require deducing T as const int, which adds something (i.e. const-ness).
The rules for template type deductions are not super straightforward, so if you want to learn all nitty-gritty details about templates, I highly recommend the book
C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis.
It's pre C++11, but nevertheless it tells you everything you can think of.
PS: you must make a differentiation between instantiation and template type deduction. The type deduction happens first, then an instantiation follows. So in your case you don't have 2 ambiguous instantiations as you may have thought initially.

Overloading reference vs const reference

I have the following code:
#include <iostream>
template <typename T>
void f(T& x)
{
std::cout << "f(T& )" << std::endl;
}
template <typename T>
void f(const T& x)
{
std::cout << "f(const T& )" << std::endl;
}
int main()
{
int a = 0;
const float b = 1.1;
f(a); // call f(T&)
f(b); // call f(const T&)
}
The output is:
f(T& )
f(const T& )
My question is: how does the compiler know which function to call? If I remove the references from the function definitions then I get an "ambiguous call" type of error, i.e. error: redefinition of 'f'. For me it looks like f(T&) can be equally well used for both calls, why is the const version unambiguously called for f(b)?
Given two competing overloads, the standard requires the compiler to select the overload that has the "best fit". (If there's no unique best overload, or if the unique best overload is inaccessible, the program is ill-formed.)
In this case, the rules are provided by §13.3.3.2 [over.ics.rank]/p3:
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.
This is the example given in the standard:
int f(const int &);
int f(int &);
int g(const int &);
int g(int);
int i;
int j = f(i); // calls f(int &)
int k = g(i); // ambiguous
In your case, const T& is more cv-qualified than T&, so by the standard, f(T&) is a better fit than f(const T&) and is selected by overload resolution.
f(T&) vs. f(T const&)
The two functions are different, in that the first signature states that any variable passed by reference may be modified by the function. So the const float cannot be passed to the first function, and the second is the only viable choice for the compiler. A nonconst variable could be passed to both, so the compiler has to chose the better fit, if there is one. The standard says, that in order to call the second function, the compiler would have to add a const to any nonconst variable, while for the first function this is not necessary. Adding const is an implicit conversion, and it is a "worse" converison (read that as more conversion steps) than adding nothing. Therefore the standard demands that the compiler picks the first function when passing nonconst variables.
In case you wonder: literals and temporaries can not be bound to nonconst references, so f(4), f("meow") and f(someFunc()) will all call the second function.
f(T) vs. f(const T)
They look different, but aren't in terms of overload resolution or function signature. Both of them are call by value, or for the compiler: pass a copy of the argument into the function. The only difference is in a function definition, that you require the variable to be constant in the function body. Any function declaration does not affect the variable definition in the function definition's signature:
void f(int); //a declaration
void f(int i); //redeclaration of the same function
void f(int const); //still the same function redeclared
void f(int const i2); //yes... a redeclaration
void f(int const i) { //at last a function definition and the copy of the argument used in the function body is required to be const
//...
}
void f(int i) { //there is only one f, so this is a redefinition!
//...
}
This is not an "ambuguos call type error", because for the compiler there is only one function and no ambiguity. The error is simply that you did defin the same funciton twice. For that reason, it is preferred in many style guides that function declarations have no top-level const, and compilers will often ignore them and not mention them in error or warning messages.

Understanding template argument deduction with rvalue/lvalue

This is a followup from function template does not recognize lvalue
Lets play with the following code:
#include <iostream>
template <class T>
void func(T&&) {
std::cout<<"in rvalue\n";
}
template <class T>
void func(const T&) {
std::cout<<"in lvalue\n";
}
int main()
{
double n=3;
func<double>(n);
func(n);
}
It prints:
in lvalue
in rvalue
I don't understand what's happening in the second call. How the compiler
resolve the template parameter ? Why isn't there any ambiguity ?
When you say func<double>(n), there's no argument deduction, since you specify the argument, and so the choice is between func(double &&) and func(const double &). The former isn't viable, because an rvalue reference cannot bind to an lvalue (namely n).
Only func(n) performs argument deduction. This is a complex topic, but in a nutshell, you have these two possible candidates:
T = double &: func(T &&) --> func(double &) (first overload)
T = double: func(const T &) --> func(const double &) (second overload)
The first overload is strictly better, because it requires one less conversion of the argument value (namely from double to const double).
The magic ingredient is the "reference collapsing", which means that T && can be an lvalue reference when T is itself a reference type (specificaly, double & && becomes double &, and that allows the first deduction to exist).

c++ template function argument deduce and function resolution

Today I just want to raise a question on C++ template function argument deduce and template function overload resolution in c++ 11 (I am using vs2010 sp1).
I have defined two template functions as below:
function #1:
template <class T>
void func(const T& arg)
{
cout << "void func(const T&)" <<endl;
}
function #2:
template <class T>
void func(T&& arg)
{
cout << "void func(T&&)" <<endl;
}
Now consider the following code:
int main() {
//I understand these first two examples:
//function #2 is selected, with T deduced as int&
//If I comment out function #2, function#1 is selected with
//T deduced as int
{int a = 0; func(a);}
//function #1 is selected, with T is deduced as int.
//If I comment out function #1, function #2 is selected,
//with T deduced as const int&.
{const int a = 0; func(a);}
//I don't understand the following examples:
//Function #2 is selected... why?
//Why not function #1 or ambiguous...
{func(0);}
//But here function #1 is selected.
//I know the literal string “feng” is lvalue expression and
//T is deduced as “const char[5]”. The const modifier is part
//of the T type not the const modifier in “const T&” declaration.
{func(“feng”)}
//Here function#2 is selected in which T is deduced as char(&)[5]
{char array[] = “feng”; func(array);}
}
I just want to know the rules behind guiding the function overloading resolution under these scenarios.
I don't agree with the two answers below.I think the const int example is different from the literal string example. I can modify the #function 1 a bit to see what’s the deduced type on earth
template <class T>
void func(const T& arg)
{
T local;
local = 0;
cout << "void func(const T&)" <<endl;
}
//the compiler compiles the code happily
//and it justify that the T is deduced as int type
const int a = 0;
func(a);
template <class T>
void func(const T& arg)
{
T local;
Local[0] = ‘a’;
cout << "void func(const T&)" <<endl;
}
//The compiler complains that “error C2734: 'local' : const object must be
//initialized if not extern
//see reference to function template instantiation
//'void func<const char[5]>(T (&))' being compiled
// with
// [
// T=const char [5]
// ]
Func(“feng”);
in the const int example, the const modifier in the “const T&” declaration eats up “the constness” of const int; while in the literal string example, I don’t know where the const modifier in the “const T&” declaration goes. It is meaningless to declare some like int& const (but it is meaningful to declare int* const)
The trick here is the const. Both F1 and F2 can accept any value of any type, but F2 is a better match in general, because it's perfect forwarding. So unless the value is a const lvalue, F2 is the best match. However, when the lvalue is const, F1 is the better match. This is why it's preferred for the const int and the string literal.
Note that overload #2 is exact match for T& and T&&. So both overloads can bind to rvalue and lvalue. In your examples overload differentiation is done mostly on constness.
//Function #2 is selected... why?
//Why not function #1 or ambiguous...
{func(0);}
0 is int&& - exact match for T&&
//But here function #1 is selected.
//I know the literal string “feng” is lvalue expression and
//T is deduced as “const char[5]”. The const modifier is part
//of the T type not the const modifier in “const T&” declaration.
{func(“feng”)}
Literal "feng" is const char(&)[5] - exact match for const T& in 1st overload. The (&) indicates that this is a reference.
//Here function#2 is selected in which T is deduced as char(&)[5]
{char array[] = “feng”; func(array);}
array - is char(&)[5] - exact match for T& in 2nd overload