Why does make_pair<int,int> fail in C++ 11?

Viewed 865

The following piece of code works fine when compiling as C++ 98, but it fails as C++ 11. Why?

#include <iostream>
#include <utility>

using namespace std;

int main()
{
    int u = 1;
    pair<int, int> p = make_pair<int, int>(0, u);
    cout << p.first << " " << p.second << "\n";
}

The error message from g++ (Debian 8.3.0-6) 8.3.0 is:

foo.cpp: In function ‘int main()’:
foo.cpp:9:45: error: no matching function for call to ‘make_pair<int, int>(int, int&)’
  pair<int, int> p = make_pair<int, int>(0, u);
                                             ^

I'm aware that I can compile this simply by removing the template specifier from make_pair and letting the compiler decide the types on its own. But I'm interested in understanding what changes from C++ 98 to C++ 11 that makes this code no longer compliant.

3 Answers

Before c++11 there was

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

you defined T1 and T2 to be: int, so int can take Lvalues and Rvalues.

Since c++11 you have

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

because T2 was defined as int, so int&& as second parameter can take only Rvalues. But u is Lvalue.

You are not supposed to pass type arguments to make_pair; it is intended to deduce its arguments. If you want to make something that creates exactly of a type, just do std::pair<int, int>.

In rvalue references and perfect forwarding was added; make_pair<int,int> has signature (int&&, int&&). These are both rvalue references, and cannot bind to an lvalue (like u).

make_pair<int, int&>(0, u) would compile, and produce a pair<int, int>, because make_pair creates a pair of value-types.

Without rvalue references in , this problem cannot happen. Probably make_pair was make_pair( A const&, B const& ) instead of make_pair( A&&, B&& ).

std::make_pair has changed between c++03 and c++11.

Your code fails as std::make_pair expects T&& and U&&, where T and U are template type parameters. Like

template <typename T, typename U>
std::pair<V1,V2> make_pair(T&& argT, U&& argU);

Still if you want to specify both of these parameter use pair<int, int>

Example -

#include <iostream>
#include <utility>
using namespace std;

int main() {
    int u = 1;
    pair<int, int> p = pair<int, int>(0, u);
    cout << p.first << " " << p.second << "\n";
}

You can refer here for more details - utility-make_pair

Related