###### tags: `C++`
# Magic std::make_pair
## use `std::make_pair` in a common method
I want to use `std::make_pair` to initilize a `std::pair` object, so I use the following code.
``` C++=
int main() {
int n=5;
std::pair<int, int> p = std::make_pair<int,int>(n,n);
}
```
However, the compilation is failed and I got the message:
```
<source>:23:53: error: cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'
23 | std::pair<int, int> p = std::make_pair<int,int>(n,n);
| ^
In file included from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_algobase.h:64,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/char_traits.h:39,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ios:40,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/ostream:38,
from /opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/iostream:39,
from <source>:1:
/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/bits/stl_pair.h:524:21: note: initializing argument 1 of 'constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = int; typename std::__decay_and_strip<_T2>::__type = int; typename std::__decay_and_strip<_Tp>::__type = int]'
524 | make_pair(_T1&& __x, _T2&& __y)
```
It means that we attempt to bind a lvalue `n` to a rvalue reference `__x`.
Therefore, I read the std::make_pair in [cppreference](https://en.cppreference.com/w/cpp/utility/pair/make_pair) and I see the definition of the make_pair.
``` cpp
template< class T1, class T2 >
constexpr std::pair<V1, V2> make_pair( T1&& t, T2&& u );
```
where
The deduced types V1 and V2 are std::decay\<T1>::type and std::decay\<T2>::type (the usual type transformations applied to arguments of functions passed by value) unless application of std::decay results in std::reference_wrapper\<X> for some type X, in which case the deduced type is X&.
Therefore, the signature of make_pair is related of the argument's type.
Let's see if we specify the int to `std::make_pair`, what do we see for the argument.
```
std::make_pair<int,int>
=>
constexpr std::pair<std::decay<int>::type, std::decay<int>::type> std::make_pair(int && t, int&& u);
=>
constexpr std::pair<int, int> std::make_pair(int&& t, int&& u);
```
It's why compiler tell as n cannot bind to rvalue reference because t is an rvalue reference argument.
After understanding the deduced rule, we have several methods to generate the std::pair<int,int>.
``` cpp=
int main() {
int n = 42;
// method 1, don't specify the type in the function
std::pair<int,int> a = std::make_pair(n,n);
std::pair<int,int> b = std::make_pair(1,2);
// method 2, specify the correct type
// 2-1: n is a lvalue reference
std::pair<int,int> c = std::make_pair<int&, int&>(n,n);
// 2-2: change n to rvalue reference
std::pair<int,int> d = std::make_pair<int, int>(std::move(n),std::move(n));
// 2-3: use a temperatory value
std::pair<int,int> e = std::make_pair<int, int>(1,2);
}
```
## use the reference in the pair
We know how to use `std::make_pair` correctly now.
However, how do we create a pair containing the reference.
The following is a possible method.
``` cpp=
int main() {
int n = 42;
std::pair<int, int&> a = std::make_pair(1, n);
}
// error message:
<source>:23:44: error: conversion from 'pair<[...],int>' to non-scalar type 'pair<[...],int&>' requested
23 | std::pair<int, int&> a = std::make_pair(1, n);
| ~~~~~~~~~~~~~~^~~~~~
```
Go back and see the usage of the make_pair
``` cpp
template< class T1, class T2 >
constexpr std::pair<V1, V2> make_pair( T1&& t, T2&& u );
```
and `V1` is `std::decay<T1>::type` so that `std::make_pair(1,n)` should return `std::pair<int,int>` but not `std::pair<int, int&>`
So, how to use std::make_pair to create a pair containing a reference?
We can refer to `std::ref` and `std::reference_wrapper` in STL.
```c++=
int main(){
int n = 42;
std::pair<int, int&> a = std::make_pair(1, std::ref(n));
std::pair<int, int&> b = std::make_pair<int, std::reference_wrapper<int>>(1, n);
}
```
In line 3, `std::ref(n)` specify `T2` as `std::reference_wrapper\<int>` and `std::decay<T2>::type` is a `int&`.
line 4 is same as line 3, we specify the `T2` explicitly.
# Take Away
Create the std::pair with std::make_pair
``` cpp=
// without any reference in the pair
int main() {
int n = 42;
// method 1, don't specify the type in the function
std::pair<int,int> a = std::make_pair(n,n);
std::pair<int,int> b = std::make_pair(1,2);
// method 2, specify the correct type
// 2-1: n is a lvalue reference
std::pair<int,int> c = std::make_pair<int&, int&>(n,n);
// 2-2: change n to rvalue reference
std::pair<int,int> d = std::make_pair<int, int>(std::move(n),std::move(n));
// 2-3: use a temperatory value
std::pair<int,int> e = std::make_pair<int, int>(1,2);
}
// with reference in the pair
int main(){
int n = 42;
std::pair<int, int&> a = std::make_pair(1, std::ref(n));
std::pair<int, int&> b = std::make_pair<int, std::reference_wrapper<int>>(1, n);
}
```