Explicit template arguments to make_pair -- legal (c++11)?

Discussion in 'C++' started by K. Frank, Jan 17, 2012.

  1. K. Frank

    K. Frank Guest

    Hello Group!

    I'm having trouble with "g++ -std=c++0x" when trying to compile

    std::make_pair<int, unsigned> (i, u)

    where I give explicit template arguments to make_pair, specifically:

    #include <utility>
    std::pair<int, unsigned> f() {
    int i = 1;
    unsigned u = 2;
    std::pair <int, unsigned> p = std::make_pair<int, unsigned> (i,
    u); // <-- legal?
    // std::pair <int, unsigned> p = std::make_pair (i, u); // <--
    this works
    return p;
    }

    This compiles fine when I just run "g++", but fails when I turn on
    experimental support for the new standard, "g++ -std=c++0x",
    giving the following error:

    C:\>g++ -std=c++0x -c pair_junk2.cpp
    pair_junk2.cpp: In function 'std::pair<int, unsigned int> f()':
    pair_junk2.cpp:5:68: error: no matching function for call to
    'make_pair(int&, unsigned int&)'
    pair_junk2.cpp:5:68: note: candidate is:
    ../lib/gcc/x86_64-w64-mingw32/4.7.0/../../../../include/c++/4.7.0/
    bits/stl_pair.h:280:5: note: template<class _T1, class _T2> constexpr
    std::pair<typename std::__decay_and_strip<_T1>::__type, typename
    std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
    ../lib/gcc/x86_64-w64-mingw32/4.7.0/../../../../include/c++/4.7.0/
    bits/stl_pair.h:280:5: note: template argument deduction/
    substitution failed:
    pair_junk2.cpp:5:68: note: cannot convert 'i' (type 'int') to
    type 'int&&'

    I am running a mingw-w64 build of g++: "g++ (GCC) 4.7.0 20110829
    (experimental)"

    (For what it's worth, the code is accepted by Comeau's online
    compiler.)

    Is "std::make_pair<int, unsigned> (i, u)" legal in general? Is this
    a difference between the old and new standards? Is this a bug
    in g++ in std=c++0x mode?

    Thanks.


    K. Frank
    K. Frank, Jan 17, 2012
    #1
    1. Advertising

  2. On 1/16/2012 8:15 PM, K. Frank wrote:
    >[..]
    > I am running a mingw-w64 build of g++: "g++ (GCC) 4.7.0 20110829
    > (experimental)"
    >
    > (For what it's worth, the code is accepted by Comeau's online
    > compiler.)
    >
    > Is "std::make_pair<int, unsigned> (i, u)" legal in general? Is this
    > a difference between the old and new standards? Is this a bug
    > in g++ in std=c++0x mode?


    It was legal before, yes? What I am about 99.8% certain of, is that the
    new Standard couldn't have made some relatively recent code (no "auto"
    or "register" in odd places) that suddenly illegal. Explicit arguments
    to function templates have always been legal and should not present a
    problem. I think it must be a bug in the compiler.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jan 17, 2012
    #2
    1. Advertising

  3. K. Frank

    SG Guest

    On Jan 17, 2:15 am, K. Frank wrote:
    >
    > I'm having trouble with "g++ -std=c++0x" when trying to compile
    >
    >    std::make_pair<int, unsigned> (i, u)
    >
    > where I give explicit template arguments to make_pair
    > [...]
    > Is "std::make_pair<int, unsigned> (i, u)" legal in general? Is this
    > a difference between the old and new standards? Is this a bug
    > in g++ in std=c++0x mode?


    Disclaimer: I havn't checked one of the recent drafts but I'm pretty
    sure about what's going on and have a satisfying workaround for you at
    the end of this post.

    The declaration (probably) changed from

    template<class T, class U>
    ... make_pair(T const& a, U const& b)

    to

    template<class T, class U>
    ... make_pair(T && a, U && b)

    in C++11. So, the committee extended make_pair by use of the perfect
    forwarding technique. This allows the reduction of unnecessary copy
    operations with the help of move semantics. If you specify T and/or U
    explicitly (and not to be lvalue references), the function will be
    expecting rvalue arguments only. Since your arguments i and u are
    lvalues and one can't initialize an rvalue reference with an lvalue
    (generally), the compiler will reject your code.

    However, the purpose of make_pair is actually to *AVOID* having to
    specify types manually. We wouldn't need make_pair if you we knew
    exactly what kind of pair we are interested in and were willing to
    specify its type parameters:

    std::pair<int, unsigned> (i, u)

    This will do exactly, what you're interested in and is even shorter to
    type. So, this change from C++03 to C++11 doesn't really pose a
    problem.


    Cheers!
    SG
    SG, Jan 17, 2012
    #3
  4. K. Frank

    K. Frank Guest

    Hi Victor and SG!

    Thank you for your comments.

    On Jan 17, 7:24 am, SG <> wrote:
    > On Jan 17, 2:15 am, K. Frank wrote:
    >
    > > I'm having trouble with "g++ -std=c++0x" when trying to compile

    >
    > >    std::make_pair<int, unsigned> (i, u)

    >
    > > where I give explicit template arguments to make_pair
    > > [...]
    > > Is "std::make_pair<int, unsigned> (i, u)" legal in general?  Is this
    > > a difference between the old and new standards?  Is this a bug
    > > in g++ in std=c++0x mode?

    >
    > Disclaimer: I havn't checked one of the recent drafts but I'm pretty
    > sure about what's going on and have a satisfying workaround for you at
    > the end of this post.
    >
    > The declaration (probably) changed from
    >
    >   template<class T, class U>
    >   ... make_pair(T const& a, U const& b)
    >
    > to
    >
    >   template<class T, class U>
    >   ... make_pair(T && a, U && b)


    This makes sense. I don't really understand the details of rvalue
    references, but when the compile error occurred, the compiler did
    complain:

    pair_junk2.cpp:5:68: note: cannot convert 'i' (type 'int') to
    type 'int&&'

    so your explanation seems reasonable.

    > in C++11.  So, the committee extended make_pair by use of the perfect
    > forwarding technique.  This allows the reduction of unnecessary copy
    > operations with the help of move semantics.  If you specify T and/or U
    > explicitly (and not to be lvalue references), the function will be
    > expecting rvalue arguments only.  Since your arguments i and u are
    > lvalues and one can't initialize an rvalue reference with an lvalue
    > (generally), the compiler will reject your code.
    >
    > However, the purpose of make_pair is actually to *AVOID* having to
    > specify types manually.  We wouldn't need make_pair if you we knew
    > exactly what kind of pair we are interested in and were willing to
    > specify its type parameters:
    >
    >   std::pair<int, unsigned> (i, u)


    Yes, this makes sense and works fine. I guess I was so fixated
    on make_pair that it didn't occur to me to use pair's constructor
    directly. Using the (explicitly templatized) constructor also
    probably expresses more directly my intent (that of wanting a
    pair of specific types).

    > This will do exactly, what you're interested in and is even shorter to
    > type.  So, this change from C++03 to C++11 doesn't really pose a
    > problem.


    From a practical point of view this isn't an issue for me. Both
    leaving the types out of make_pair and your suggestion of using
    the constructor work fine.

    But, coming back to Victor's question, does this represent a bug
    in the compiler (or maybe a defect in the new standard)? Generally
    the new standards tries to avoid breaking previously legal code,
    at least without good reason.

    I don't understand rvalue references well enough to have an opinion
    about whether this issue is inherent in extended functionality of
    the new make_pair, or whether it could be avoided somehow.

    Does anyone know if this is a know issue and is accepted as the
    necessary price to pay for the new make_pair? (I will say, that,
    except for the legacy-code issue, the behavior of the new make_pair
    doesn't seem to me to be a problem.)

    Also, I've only tried this with "g++ -std=c++0x". Would anyone
    know whether other compilers with c++11 support show the same
    issue?

    > Cheers!
    > SG


    Thanks again.


    K. Frank
    K. Frank, Jan 17, 2012
    #4
  5. K. Frank

    SG Guest

    On Jan 17, 7:24 pm, K. Frank wrote:
    > Hi Victor and SG!
    > Thank you for your comments.
    > [...]
    > SG wrote:
    > >
    > > The declaration (probably) changed from
    > >
    > >   template<class T, class U>
    > >   ... make_pair(T const& a, U const& b)


    Correction: In C++03 there is no "const&". Well, the standard is not
    specific about whether make_pair takes its parameters by value or by
    reference. But it specifies its behaviur in terms of pass-by-value
    while allowing implementations to save unnecessary copying.

    > > to
    > >
    > >   template<class T, class U>
    > >   ... make_pair(T && a, U && b)

    >
    > [...]
    >
    > > in C++11.  So, the committee extended make_pair by use of the perfect
    > > forwarding technique.  This allows the reduction of unnecessary copy
    > > operations with the help of move semantics.  If you specify T and/or U
    > > explicitly (and not to be lvalue references), the function will be
    > > expecting rvalue arguments only.  Since your arguments i and u are
    > > lvalues and one can't initialize an rvalue reference with an lvalue
    > > (generally), the compiler will reject your code.
    > > [...]

    > [...]
    > From a practical point of view this isn't an issue for me.  Both
    > leaving the types out of make_pair and your suggestion of using
    > the constructor work fine.
    >
    > But, coming back to Victor's question, does this represent a bug
    > in the compiler (or maybe a defect in the new standard)?  Generally
    > the new standards tries to avoid breaking previously legal code,
    > at least without good reason.


    Compiler bug? No. Every conforming C++11 compiler (or a close
    approximation thereof) has to reject the code for the reasons I
    mentioned earlier.

    Standard defect? In my opinion it's perfectly acceptable. The only
    real use case of make_pair is to let the compiler figure out the types
    to save typing. That's what it has been designed to do and that's
    what still works -- better than ever.

    > I don't understand rvalue references well enough to have an opinion
    > about whether this issue is inherent in extended functionality of
    > the new make_pair, or whether it could be avoided somehow.


    No. Obviously, there is a relationship between the template
    parameters of make_pair and type parameters of pair for the return
    value. But in C++11 this relationship is "far less direct" than one
    might expect. There are two things to consider here:

    (1) perfect forwarding requires the use of && where the "lvalueness"
    of arguments is also encoded in form of template type parameters:
    An lvalue argument makes template parameter deduction chose an
    lvalue REFERENCE type as type parameter in this case.

    (2) we want make_pair to perform certain type transformations:

    make_pair param pair param
    type T type
    -------------------------------------
    reference_wrapper<X> X& ("reference unpacking")
    const reference_wrapper<X> X& ("reference unpacking")
    X (&)[N] X* ("decay copy behaviour")

    Perfect forwarding is desirable for efficiency reasons. The type
    transformations come in handy when string literals are used as
    arguments or you really want to create a pair or tuple with a
    reference as member:

    int i = 99;
    auto p = make_pair(ref(i),"hello");
    p.first++;
    assert(i==100);

    The decltype(p) will be pair<int&,const char*>.

    > Does anyone know if this is a know issue


    I don't know.

    > and is accepted as the
    > necessary price to pay for the new make_pair?


    I don't know.

    > (I will say, that,
    > except for the legacy-code issue, the behavior of the new make_pair
    > doesn't seem to me to be a problem.)


    I agree.


    Cheers!
    SG
    SG, Jan 17, 2012
    #5
  6. K. Frank

    K. Frank Guest

    Hello SG!

    Thank you for your helpful explanation.

    On Jan 17, 3:23 pm, SG <> wrote:
    > On Jan 17, 7:24 pm, K. Frank wrote:
    > ...
    > > But, coming back to Victor's question, does this represent a bug
    > > in the compiler (or maybe a defect in the new standard)?  Generally
    > > the new standards tries to avoid breaking previously legal code,
    > > at least without good reason.

    >
    > Compiler bug?  No.  Every conforming C++11 compiler (or a close
    > approximation thereof) has to reject the code for the reasons I
    > mentioned earlier.
    >
    > Standard defect?  In my opinion it's perfectly acceptable.  The only
    > real use case of make_pair is to let the compiler figure out the types
    > to save typing.  That's what it has been designed to do and that's
    > what still works -- better than ever.


    Makes sense. Thanks.

    > > I don't understand rvalue references well enough to have an opinion
    > > about whether this issue is inherent in extended functionality of
    > > the new make_pair, or whether it could be avoided somehow.

    >
    > No.  Obviously, there is a relationship between the template
    > parameters of make_pair and type parameters of pair for the return
    > value.  But in C++11 this relationship is "far less direct" than one
    > might expect.  There are two things to consider here:
    >
    > (1) perfect forwarding requires the use of && where the "lvalueness"
    >     of arguments is also encoded in form of template type parameters:
    >     An lvalue argument makes template parameter deduction chose an
    >     lvalue REFERENCE type as type parameter in this case.
    >
    > (2) we want make_pair to perform certain type transformations:
    >
    >        make_pair param            pair param
    >            type T                    type
    >        -------------------------------------
    >        reference_wrapper<X>           X&   ("reference unpacking")
    >        const reference_wrapper<X>     X&   ("reference unpacking")
    >        X (&)[N]                       X*   ("decay copy behaviour")
    >
    > Perfect forwarding is desirable for efficiency reasons.  The type
    > transformations come in handy when string literals are used as
    > arguments or you really want to create a pair or tuple with a
    > reference as member:
    >
    >   int i = 99;
    >   auto p = make_pair(ref(i),"hello");
    >   p.first++;
    >   assert(i==100);
    >
    > The decltype(p) will be pair<int&,const char*>.


    Again, very helpful.

    I guess slowly (but not necessarily surely) I'm learning about
    rvalue references and their various uses.

    > > Does anyone know if this is a know issue

    >
    > I don't know.


    Upon reflection, I bet is was well understood when the change
    was proposed.

    > > and is accepted as the
    > > necessary price to pay for the new make_pair?

    >
    > I don't know.
    >
    > > (I will say, that,
    > > except for the legacy-code issue, the behavior of the new make_pair
    > > doesn't seem to me to be a problem.)

    >
    > I agree.
    >
    > Cheers!
    > SG



    Cheers back at ya!


    K. Frank
    K. Frank, Jan 18, 2012
    #6
  7. K. Frank

    Marc Guest

    SG wrote:

    >> >   template<class T, class U>
    >> >   ... make_pair(T const& a, U const& b)

    >
    > Correction: In C++03 there is no "const&". Well, the standard is not
    > specific about whether make_pair takes its parameters by value or by
    > reference. But it specifies its behaviur in terms of pass-by-value
    > while allowing implementations to save unnecessary copying.


    I think that was done for arrays (in C++11 it uses std::decay
    instead).

    > Standard defect? In my opinion it's perfectly acceptable. The only
    > real use case of make_pair is to let the compiler figure out the types
    > to save typing. That's what it has been designed to do and that's
    > what still works -- better than ever.


    The one case I can think of is if you want to construct a pair and you
    want to specify the first type but let the compiler guess the second.
    Not the most frequent use...

    >> Does anyone know if this is a know issue


    I'm pretty sure it is.
    Marc, Jan 18, 2012
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. JustSomeGuy

    pair and make_pair

    JustSomeGuy, Jul 7, 2004, in forum: C++
    Replies:
    3
    Views:
    19,008
    Darkay Li
    Jul 7, 2004
  2. J.T. Conklin
    Replies:
    1
    Views:
    431
    David Hilsee
    Aug 11, 2004
  3. John Black

    can not reference make_pair?

    John Black, Nov 17, 2004, in forum: C++
    Replies:
    2
    Views:
    580
    ES Kim
    Nov 17, 2004
  4. Replies:
    3
    Views:
    5,811
    Pete Becker
    Mar 7, 2005
  5. James Daughtry
    Replies:
    1
    Views:
    357
    Barry
    Sep 18, 2008
Loading...

Share This Page