3

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.

giusti
  • 3,156
  • 3
  • 29
  • 44

3 Answers3

7

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.

rafix07
  • 20,001
  • 3
  • 20
  • 33
2

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&& ).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
2

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

Aman Raj
  • 239
  • 3
  • 15
  • You version compiles with `-std=c++98`. So you could always have instantiated the pair with the constructor. Why was `make_pair` required? – giusti Jun 27 '19 at 06:24
  • Using `make_pair` you can use curly braces to simply add elements without typing whole thing. See this [link](https://stackoverflow.com/questions/9270563/what-is-the-purpose-of-stdmake-pair-vs-the-constructor-of-stdpair) – Aman Raj Jun 27 '19 at 15:23