1

Maybe I'm being stupid, but I don't see what the problem with this code is. I'm starting to resort to doubting my tools. I'm using Clang (C++11), and its libc++. If it's my fault, I apologise and thank in advance whoever points out my stupidity, but if it's not, maybe this is a deeper issue..

std::map<int, bool> map_;

map_.insert(std::make_pair<int, bool>(5, true)); //Use a literal, compiles OK

int x = 5;
map_.insert(std::make_pair<int, bool>(x, true)); //Use a local of same type, compile error: 'no known conversion from 'int' to 'int &&' for 1st argument'
Coran
  • 360
  • 3
  • 11
  • 4
    You should not provide template arguments, but let deduction do its job: `std::make_pair(x, true)` – juanchopanza Jan 19 '14 at 23:54
  • `std::make_pair` would normally take that and give it a type of `int & &&`, or `int &`. Now you've gone and made it do `int &&`, which can't be used with an lvalue. – chris Jan 19 '14 at 23:55
  • Yeah, that fixes it. But I wonder why.. enforcing the template version of the function that matches the arguments should yield the same implementation, surely? – Coran Jan 19 '14 at 23:56
  • @ Chris. I see, so the definition adds the & on to the passed type, adding a further level of indirection.. that makes sense now! Thanks – Coran Jan 19 '14 at 23:58
  • @Coran, See the term "universal reference" and you'll find all sorts of good resources. – chris Jan 19 '14 at 23:58
  • Yes, it appears to be a duplicate, and the other has a more expanded explanation. Though the answer from 0x499602D2 is very good! Thank you – Coran Jan 20 '14 at 00:05

1 Answers1

8

std::make_pair takes a "universal reference" to its arguments. A universal reference can bind to pretty much anything. This is the actual signature:

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

When you explicitly supply the type (unnecessarily I might add), it turns the function call into this:

... ( int&& t, bool&& u );

Meaning the arguments are no longer universal references but rvalue-references. Rvalue-references can only bind to rvalues, not lvalues, hence the error for the first argument.

The solution to this issue is to allow template argument deduction to do its job:

map_.insert(std::make_pair(x, true));
David G
  • 94,763
  • 41
  • 167
  • 253