>> " << "int mycall(const X& a)" << std::endl; return 0; } template >> " << "int mycall(const X& a)" << std::endl; return 0; } template >> " << "int mycall(const X& a)" << std::endl; return 0; } template

perfect forwarding confusion

71 Views Asked by At

Hello everyone,

template<typename X>
int mycall(const X& a)
{
    std::cout << ">>>  " << "int mycall(const X& a)" << std::endl;
    return 0;
}

template<typename X>
int mycall(X&& a)
{
    std::cout << ">>>  " << "int mycall(X&& a)" << std::endl;
    return 0;
}



template <typename T>
class CClass
{
public:

    CClass(T t) : m_t{t}
    {
    }

    template<typename U>
    auto operator()(U&& t)
    {
        mycall(std::forward<U>(t));
    }


private:

    T m_t;
};



class A{};

int main()
{

    CClass cc{5};

    //1..
    int x = 9;    
    cc(x);
    
    cc(10);
    cc(A{});

    //4..
    A a{};
    cc(a);

    return 0;
}

output:

>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)

In the example above, for the first and fourth calls, I initially expected that the universal reference would deduce as an lvalue reference, leading to the mycall(const T&) version being called due to perfect forwarding. However, I observed that the mycall(T&&) version is called instead.

When I removed the const qualifier, changing the function to mycall(T&), the first and fourth calls are forwarded as lvalue references, and as a result, the mycall(T&) version is called as expected. What is the effect of the const qualifier here? Why is the argument forwarded as an rvalue reference?

1

There are 1 best solutions below

0
463035818_is_not_an_ai On

As mentioned in comments, int mycall(X&& a) is also using a forwarding reference, hence it is prefered over the other template.

Forwarding requires the template argument to be deduced, so one way to get the desired output is to not let it be deduced again:

template<typename U>
auto operator()(U&& t)
{
    mycall<U>(std::forward<U>(t));
}

Resulting output:

>>>  int mycall(const X& a)
>>>  int mycall(X&& a)
>>>  int mycall(X&& a)
>>>  int mycall(const X& a)