changFeng
changFeng

Reputation: 49

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)

Upvotes: 4

Views: 465

Answers (2)

Leonid Volnitsky
Leonid Volnitsky

Reputation: 9144

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

Upvotes: 1

Puppy
Puppy

Reputation: 147036

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.

Upvotes: 5

Related Questions