none
Why doesn't this compile anymore?

    Question

  • #include<string>

    #include <vector>
    #include <map>
    #include <algorithm>
    #include <iterator>


    {

      using namespace std;

     

      vector<string> a;

      vector<string> b;

      map<string, string> c;

     

      // Populate vectors

     

      transform(a.begin(), a.end(), b.begin(), inserter(c, c.begin()), make_pair<string, string>);

    }

     

    The compiler in Visual Studio 2010 fails to match the template to the proper overloaded template function for transform:

     

    template<class _InIt1,
        class _InIt2,
        class _OutIt,
        class _Fn2> inline
        _OutIt transform(_InIt1 _First1, _InIt1 _Last1,
            _InIt2 _First2, _OutIt _Dest, _Fn2 _Func);

     

    Why is this.  I assume this version is more conformant that the one upon which this worked (Visual Studio 2005).  So why is this code no longer valid?  I've been trying google for the past day and have found no solution.  Any help would be greatly appreciated.  Thanks!

    • Edited by WorkingHorse Thursday, September 30, 2010 4:18 PM
    Wednesday, September 29, 2010 3:10 PM

Answers

  • There is a bug in Visual Studio 10 which has been reported.  As mentioned later in this thread, the main problem is with the make_pair overload not being correctly resolved even when type-cast because of the multiple overloads, though template resolution should correctly identify the template to use from the explicit argument list.  In any case, since VS 10 now supports ISO C++0x Draft specification for Lambda expressions, the transform can be rewritten as follows:

     

    transform(a.begin(), a.end(), b.begin(), inserter(c, c.begin()), [] (string &key, string &value) throw() { return make_pair(key, value); });

    • Marked as answer by WorkingHorse Thursday, September 30, 2010 5:06 PM
    Thursday, September 30, 2010 5:06 PM

All replies

  • Make sure you have included all of the required headers.
    VC++ 2010 now requires that you explicitly include headers
    which were implicitly (automatically) included in prior
    versions. See:

    http://blogs.msdn.com/b/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx

    - Wayne
    Wednesday, September 29, 2010 7:31 PM
  • On 29/09/2010 21:31, WayneAKing wrote:

    Make sure you have included all of the required headers.
    VC++ 2010 now requires that you explicitly include headers
    which were implicitly (automatically) included in prior
    versions. See:

    I don't think that's the problem.

    The following code compiles fine on VC9 but not on VC10:

    #include <string>
    #include <vector>
    #include <map>
    #include <algorithm>    // transform
    #include <iterator>     // inserter
    #include <utility>      // make_pair
    #include <iostream>     // cout
     using namespace std;
     int main()
    {
      vector<string> a;
      vector<string> b;
      map<string, string> c;
       a.push_back("ciao");
      a.push_back("mondo");
      a.push_back("prova");
       b.push_back("hello");
      b.push_back("world");
      b.push_back("test");
       transform(a.begin(), a.end(), b.begin(), inserter(c, c.begin()),
    make_pair<string, string>);
       for( map<string, string>::iterator it = c.begin(); it != c.end(); ++it)
          cout << "(" << it->first << "," << it->second << ")" << endl;
       return 0;
    }
     

    The following is the error message:

    ----[begin]----
    test.cpp(28) : error C2914: 'std::transform' : cannot deduce template argument
    as function argument is ambiguous
    test.cpp(28) : error C2784: '_OutIt std::transform(_InIt1,_InIt1,_InIt2,_OutIt,
    _Fn2)' : could not deduce template argument for '_OutIt' from 'std::insert_itera
    tor<_Container>'
            with
            [
                _Container=std::map<std::string,std::string>
            ]
            C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\algorithm
    (1155) : see declaration of 'std::transform'
    test.cpp(28) : error C2780: '_OutIt std::transform(_InIt,_InIt,_OutIt,_Fn1)' :
    expects 4 arguments - 5 provided
            C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\algorithm
    (1051) : see declaration of 'std::transform'
    ----[end]----
     So, there must be some more subtle template machinery involved...

    Giovanni

    Wednesday, September 29, 2010 10:38 PM
  • Hi,

    What about if you change that line to this.

    insert_iterator< map<string, string> > Iter(c, c.begin());

    transform(a.begin(), a.end(), b.begin(), Iter, make_pair<string, string>);

     

    RenJie

    Thursday, September 30, 2010 1:07 AM
  • The problem is that make_pair has overloads for all combinations of r-values and l-values. I believe this is a mistake in the standard library implementation, as only a single perfect-forwarding function should be needed (reference collapsing rules will handle the l-values properly).

    Paging Stephan for confirmation... In the meantime, I suggest submitting a bug report on MS Connect.

    Thursday, September 30, 2010 3:41 AM
  • pair experienced extreme code churn in VC10, as the Working Paper's specification was enormously complicated and continuously changing. We got it to a point where it basically works, but corner cases still act squirrely.

    According to N3126, make_pair<const string&, const string&> should work. make_pair<string, string> will not, as that will instantiate a function taking (string&&, string&&) which wants only modifiable rvalues (and vector elements are lvalues).

    In general, I advise against using explicit template arguments with function templates, except when they're specifically designed for that (e.g. forward<T>(t), make_shared<T>(args), both of which require the explicit template argument).  For example, when actually calling make_pair(x, y) or swap(x, y), explicit template arguments should never be used (they defeat the point of make_pair in the first case, and are allowed to cause explosions in the second case).  In this case you want a function pointer, so I see why you're using the explicit template arguments, but I still recommend a lambda.

    We're revamping pair in VC11, which should fix this, but if you file a Connect bug we'll be able to contact you when we've verified the fix.

    Thursday, September 30, 2010 4:45 AM
  • Thanks, renjielou, but that didn't work.  See below, it's closer to the mark.
    Thursday, September 30, 2010 4:21 PM
  • The headers were in my code, I just didn't want to waste space including them in my question, but they're here now.
    Thursday, September 30, 2010 4:22 PM
  • Did it yesterday on the off-chance that this was a bug.  Thanks for the advice!
    Thursday, September 30, 2010 4:22 PM
  • Did it yesterday on the off-chance that this was a bug.  Thanks for the advice!
    Please post a link to your bug submission here so we can validate it/vote it up.
    Thursday, September 30, 2010 4:24 PM
  • Thank you very kindly Stephan.  I have submitted the bug with the sample code though this is only 1 of the problems I'm having; many of the others involve boost bind which IIRC is now natively supported via C++0x through a new grammatical construct (well, lambda expressions really, I suppose).  But all that said, changing the make_pair template parameters to const string & didn't work either, alas.

     

    Off-hand I also tried creating an alias for the make_pair function and this also failed overloaded resolution:

    map<string, string>::value_type (*my_make_pair)(const string &, const string &) = make_pair<const string &, const string &>;

    Not even with an explicit cast of the template:

     

    map<string, string>::value_type (*my_make_pair)(const string &, const string &) = (map<string, string>::value_type (*)(const string &, const string &))&make_pair<const string &, const string &>;

    Thursday, September 30, 2010 4:37 PM
  • many of the others involve boost bind which IIRC is now natively supported via C++0x through a new grammatical construct (well, lambda expressions really, I suppose).

    What version of boost? boost 1.43+'s bind works fine with VC++ 2010. Lambdas are one alternative to boost::bind -- also consider using boost.phoenix or std::bind.

     

    But all that said, changing the make_pair template parameters to const string & didn't work either, alas.

    Stephan noted that that workaround should work according to N3126; however, VC++ 2010 is based on N3000, not N3126. My first response in this thread summarizes the problem with VC++'s current implementation, for which I cannot think of any workaround involving calling the function directly; i.e., every workaround I can think of involves wrapping make_pair with a functor/lambda or a non-template function (or a non-rvalue-aware template function).

    Thursday, September 30, 2010 4:47 PM
  • There is a bug in Visual Studio 10 which has been reported.  As mentioned later in this thread, the main problem is with the make_pair overload not being correctly resolved even when type-cast because of the multiple overloads, though template resolution should correctly identify the template to use from the explicit argument list.  In any case, since VS 10 now supports ISO C++0x Draft specification for Lambda expressions, the transform can be rewritten as follows:

     

    transform(a.begin(), a.end(), b.begin(), inserter(c, c.begin()), [] (string &key, string &value) throw() { return make_pair(key, value); });

    • Marked as answer by WorkingHorse Thursday, September 30, 2010 5:06 PM
    Thursday, September 30, 2010 5:06 PM