Search code examples
c++templatestemplate-specializationforwarding-reference

Why is template parameter a reference in this case?


Stubled upon a weird behaviour when playing with std::forward. Here is a small example:

#include <type_traits>
#include <iostream>

template <typename A>
void func(A&&)
{
    std::cout
        << std::is_pointer<A>::value
        << std::is_lvalue_reference<A>::value
        << std::is_rvalue_reference<A>::value
        << std::endl;
    using B = typename std::remove_reference<A>::type;
    std::cout
        << std::is_pointer<B>::value
        << std::is_lvalue_reference<B>::value
        << std::is_rvalue_reference<B>::value
        << std::endl;
}

int main()
{
    int* p = nullptr;
    func(p);
}

It prints 010 and 100, meaning A is a reference and not a pointer, while std::remove_reference<A> is a pointer as expected.

But why is it so? I thought that A would be a pointer and A&& a reference inside the function body. Also, what types are A& and A&& if this is the case?


Solution

  • This is how forwarding reference works; when being passed an lvalue, the template parameter A will be deduced as an lvalue-reference. For this case, it's int*&, i.e. an lvalue-reference to pointer. (After reference collapsing, the function parameter's type would be int*& too.)

    When being passed an rvalue, A will be deduced as non-reference type. For example if you pass an rvalue with type int*, A will be deduced as int*. (Then the function parameter's type would be int*&&.)