I was using forwarding references in my code when I encountered something that I don’t understand.
Example Code
To illustrate the phenomenon I wrote this simplified version of my scenario:
#include <iostream>
template <typename T>
struct Cls
{
static void func(T& b)
{
std::cout << 1 << std::endl;
}
};
template <>
struct Cls<int>
{
static void func(int& b)
{
std::cout << 2 << std::endl;
}
};
template <typename T>
void some_func(T&& a)
{
Cls<T>::func(a);
}
int main()
{
int i{3};
some_func(i);
some_func(3);
}
My Understanding
My understanding of a universal references is that they can be either an lvalue
or an rvalue
.
(A) In my head, this means that the first call (some_func(i);
) should access a version of the function where the type of a
is T&
(in this particular case: int&
), since the passed variable i
is an lvalue
of type int
. Because T
is int
, and since there is a specialized function Cls<int>::func(int&)
, there should be a match and output should be 2
.
(B) The second call (some_func(3);
) should access a version where the type of a
is T&&
(in this case: int&&
). I was not entirely sure what the output here would be.
The actual output I got was:
> 1
> 2
Note that the behaviour is the same even for non-primitive types T
.
Questions
- Does the compiler instantiate different versions of
some_func()
depending on passed reference types? I.e., one forsome_func(int& a)
and one forsome_func(int&& a)
? Or is it actually some sort of new reference type within the same instantiated function? - Why is the first output
1
? Why is the specialization not used? Is my interpretation in (A) incorrect? In any caseT
should beint
, so how is the generic implementation selected instead when they are otherwise identical? - Why is the second output
2
? Considering that the first call was unable to match with the specialization when the types are identical (int&
), why should it be able to match when there is a mismatch (int&
andint&&
)? - Has this got something to do with the fact that
a
is anxvalue
in both cases? I.e., that thervalue
may be interpreted as anlvalue
because it is intermediately stored ina
? This would explain why the second call outputs2
, but not why the first call does not?
Thanks in advance.
3