Search code examples
c++c++11templatestemplate-argument-deductionforwarding-reference

how can l-values be passed to std::make_pair


In std::make_pair there is only one implementation C++14 onwards

template< class T1, class T2 > constexpr std::pair<V1,V2> make_pair( T1&& t, T2&& u );

Both parameters are R-value references and according to this

R-values references cannot be initialized with l-values.

    int i = 1;
    char ch = 'a';
    std::unordered_map<int, char> mp;
    mp.insert(make_pair<int,char>(i, ch));

So when I try to use make_pair as in the above code it correctly throws an error error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'.

However it works perfectly for the above code if I change drop the template arguments and call it as

mp.insert(make_pair(i, ch));

I'm confused how this works as i and ch both are L-values. Does template argument resolution convert L-values to R-values or like how does this work?


Solution

  • The parameters of make_pair are not declared as rvalue-reference, but forwarding reference.

    Forwarding references are a special kind of references that preserve the value category of a function argument, making it possible to forward it by means of std::forward. Forwarding references are either:

    1. function parameter of a function template declared as rvalue reference to cv-unqualified type template parameter of that same function template:

    Forwarding referece works with both lvalues and rvalues, with the help of template argument deduction. When being passed an lvalue, the template parameter would be deduced as lvalue-reference, after reference collapsing, the function parameter is lvalue-reference too. When being passing an rvalue, the template parameter would be deduced as non-reference, the function parameter is rvalue-reference.

    On the other hand, if you specify the template argument explicitly like make_pair<int,char>(...), the function parameter become rvalue-reference accordingly.