Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Explicit template arguments to make_pair -- legal (c++11)?

Reply
Thread Tools

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

 
 
K. Frank
Guest
Posts: n/a
 
      01-17-2012
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:air<int, unsigned> f() {
int i = 1;
unsigned u = 2;
std:air <int, unsigned> p = std::make_pair<int, unsigned> (i,
u); // <-- legal?
// std:air <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:air<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:air<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
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      01-17-2012
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
 
Reply With Quote
 
 
 
 
SG
Guest
Posts: n/a
 
      01-17-2012
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:air<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
 
Reply With Quote
 
K. Frank
Guest
Posts: n/a
 
      01-17-2012
Hi Victor and SG!

Thank you for your comments.

On Jan 17, 7:24*am, SG <(E-Mail Removed)> 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:air<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
 
Reply With Quote
 
SG
Guest
Posts: n/a
 
      01-17-2012
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
 
Reply With Quote
 
K. Frank
Guest
Posts: n/a
 
      01-18-2012
Hello SG!

Thank you for your helpful explanation.

On Jan 17, 3:23*pm, SG <(E-Mail Removed)> 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
 
Reply With Quote
 
Marc
Guest
Posts: n/a
 
      01-18-2012
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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Explicit template arguments for operator() James Daughtry C++ 1 09-18-2008 06:45 AM
query on std::make_pair() mark.van.dijk@perform-sol.com C++ 3 03-07-2005 09:01 PM
can not reference make_pair? John Black C++ 2 11-17-2004 01:31 AM
Is explicit template qualification required for explicit delete? J.T. Conklin C++ 1 08-11-2004 02:06 AM
pair and make_pair JustSomeGuy C++ 3 07-07-2004 09:30 AM



Advertisments