Home Dashboard Directory Help
Search

std::make_pair error in VC11 by whetstone


Status: 

Closed
 as By Design Help for as By Design


2
1
Sign in
to vote
Type: Bug
ID: 691756
Opened: 9/29/2011 1:39:11 PM
Access Restriction: Public
Moderator Decision: Sent to Engineering Team for consideration
0
Workaround(s)
view
1
User(s) can reproduce this bug

Description

This compiles ok in VC9
but I get an error when compiling in VC11
-----------------------------------------------------

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

int main() {
    string ht = "hello";
    pair<double,string> ps;
    ps = make_pair<int,string>(1,ht);
    cout << ps.first << " " << ps.second << endl;
    return 0;
}
Details
Sign in to post a comment.
Posted by Microsoft on 10/3/2011 at 4:57 PM
Hi,

Thanks for reporting this issue. I'm resolving it as By Design because this is a breaking change between the 2003 and 2011 C++ Standards, which has been correctly implemented in VC11. Quoting myself from a recent VCBlog comment:

"make_pair()'s signature has changed:

C++03: template <class T1, class T2> pair<T1, T2> make_pair(T1 x, T2 y);

C++11: template <class T1, class T2> pair<V1, V2> make_pair(T1&& x, T2&& y);

There are several subtleties in both the C++03 and C++11 versions (C++03 taking values - changed from C++98 - and C++11 returning decayed types). As I recall, VC10 had four overloads, which may or may not have corresponded to a Working Paper at some point in time, but the final version of C++11 specifies the single function template above, and that's what we've implemented in VC11. It's Saturday, so I hope you won't mind if I skip directly to the high-level summary:

C++11 make_pair() is now a perfect forwarding function. This is a good thing (it's more efficient), but it's also incompatible with most uses of explicit template arguments. As it turns out, that's fine because make_pair()'s whole purpose in life is to be used WITHOUT explicit template arguments.

Here's why make_pair() exists. You can always write pair<A, B>(a, b) to construct a temporary pair. But you've already got a and b, and the compiler knows their types, so having to specify A and B again is annoyingly verbose (as usual, it could easily be pair<string, shared_ptr<Polygon>> or whatever). There's no such thing as "template argument deduction for class templates", so you can't write pair(a, b), but there is for function templates. Therefore, when you need a temporary pair, you can write make_pair(a, b). Giving explicit template arguments to make_pair() is unnecessary, and defeats its purpose.

(Very rarely, when you need more control over the pair's type, you can say pair<unsigned short, unsigned short>(17, 29). Again, saying make_pair here would be more verbose.)

This is one of a few breaking changes in the Standard Library that I'm aware of (the other major ones are immutable sets, and 2D vector construction).

This is also a special case of a general rule - explicit template arguments shouldn't be given to function templates, except when they're specifically designed for it - for example, forward<T>(t) and make_shared<T>(args, args, args). Notice that in make_shared()'s case, only the object type is explicit - the argument types should be implicitly deduced. When you give explicit template arguments to function templates that weren't designed for it, you'll tend to run into trouble with perfect forwarders (where you end up generating the wrong type), other overloads (where you end up triggering compiler errors in unrelated code), and helper functions (where your explicit template arguments don't reach). Just let template argument deduction do its job, and all will be well."

In your case, here are two possible fixes:

C:\Temp>type kitty.cpp
#include <iostream>
#include <ostream>
#include <string>
#include <utility>
using namespace std;

int main() {
    string ht = "hello";
    pair<double, string> ps;

#if defined(FIX1)
    ps = pair<int, string>(1, ht);
#elif defined(FIX2)
    ps = make_pair(1, ht);
#else
    ps = make_pair<int, string>(1, ht);
#endif

    cout << ps.first << " " << ps.second << endl;
}

C:\Temp>cl /EHsc /nologo /W4 kitty.cpp && kitty
kitty.cpp
kitty.cpp(16) : error C2664: 'std::make_pair' : cannot convert parameter 2 from 'std::string' to 'std::string &&'
        You cannot bind an lvalue to an rvalue reference

C:\Temp>cl /EHsc /nologo /W4 kitty.cpp /DFIX1 && kitty
kitty.cpp
1 hello

C:\Temp>cl /EHsc /nologo /W4 kitty.cpp /DFIX2 && kitty
kitty.cpp
1 hello

Both FIX1 and FIX2 construct a temporary pair<int, string>, which is then converted during assignment to pair<double, string>.

I personally recommend FIX2.

If you have any further questions, feel free to E-mail me at stl@microsoft.com .

Stephan T. Lavavej
Visual C++ Libraries Developer
Posted by Mike Danes on 10/1/2011 at 3:02 AM
That's by design, the C++ 11 standard only includes a make_pair(T1 &&, T2 &&) overload, it doesn't have make_pair(T1 &, T2 &). It works fine if you don't specify the template arguments and let template argument deduction do its job.
Posted by MS-Moderator07 [Feedback Moderator] on 9/29/2011 at 10:44 PM
Thanks for your feedback.

We are rerouting this issue to the appropriate group within the Visual Studio Product Team for triage and resolution. These specialized experts will follow-up with your issue.

Posted by MS-Moderator01 on 9/29/2011 at 2:42 PM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.