Explicit template arguments in std::make_pair

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev
Hi,

This simple program fails to compile with -std=c++11, but compiles ok
with c++03. This seems consistent between libc++/libstdc++. Is this due
to a change in the standard? What is the reason behind it?



#include <utility>

std::pair<int,unsigned> good(unsigned L) {
   return std::make_pair(0, L);
}

std::pair<int,unsigned> bad(unsigned L) {
   return std::make_pair<int,unsigned>(0, L);
}


clang++ -c -std=c++11 pp.cpp -stdlib=libc++
pp.cpp:8:10: error: no matching function for call to 'make_pair'
   return std::make_pair<int,unsigned>(0, L);
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/w/c/org/bin/../include/c++/v1/utility:639:1: note: candidate function not
       viable: no known conversion from 'unsigned int' to 'unsigned int
&&' for
       2nd argument
make_pair(_T1&& __t1, _T2&& __t2)
^
1 error generated.


-Krzysztof

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev
Hi Krzysztof,

The reason is that in C++03 make_pair looked like this

    template <class T1, class T2>
    pair<T1, T2> make_pair(T1 x, T2 y);

while in C++11 onwards looks like this

     template <class T1, class T2>
     pair<V1, V2> make_pair(T1&& x, T2&& y)

where in libcxx (similarly for libstdc++) V1 and V2 are implemented like

     pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>

because the C++ standard dictates a more sophisticated (compile-time computed) type for V1 and V2.
 
This implies that if you define T1 and T2 in the template-argument list of the function call, you are always going to get rvalue references in the parameter types (in your example 'int&&' and 'unsigned int&&' respectively).
Conversely, if you let template-argument deduction to infer T1 and T2, it will infer

  std::pair<int, unsigned int> std::make_pair<int, unsigned int &>(int &&, unsigned int &);

because of the C++11 rules about type deduction involving parameter types of the form Type&&.

I'm not an expert in this area but this behaviour looks to me as expected and matches the C++ view of generic programming in which you should not constraint (in this case using template-arguments) if not needed.

Hope this answers your question.

Kind regards,
Roger

> -----Original Message-----
> From: cfe-dev [mailto:[hidden email]] On Behalf Of
> Krzysztof Parzyszek via cfe-dev
> Sent: 16 November 2017 17:21
> To: Clang Dev
> Subject: [cfe-dev] Explicit template arguments in std::make_pair
>
> Hi,
>
> This simple program fails to compile with -std=c++11, but compiles ok
> with c++03. This seems consistent between libc++/libstdc++. Is this due
> to a change in the standard? What is the reason behind it?
>
>
>
> #include <utility>
>
> std::pair<int,unsigned> good(unsigned L) {
>    return std::make_pair(0, L);
> }
>
> std::pair<int,unsigned> bad(unsigned L) {
>    return std::make_pair<int,unsigned>(0, L);
> }
>
>
> clang++ -c -std=c++11 pp.cpp -stdlib=libc++
> pp.cpp:8:10: error: no matching function for call to 'make_pair'
>    return std::make_pair<int,unsigned>(0, L);
>           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
> /w/c/org/bin/../include/c++/v1/utility:639:1: note: candidate function not
>        viable: no known conversion from 'unsigned int' to 'unsigned int
> &&' for
>        2nd argument
> make_pair(_T1&& __t1, _T2&& __t2)
> ^
> 1 error generated.
>
>
> -Krzysztof
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev
This reminds me of STL's presentation "Don't help the compiler":

https://www.youtube.com/watch?v=AKtHxKJRwp4

Csaba

On Thu, Nov 16, 2017 at 6:39 PM, Roger Ferrer Ibanez via cfe-dev
<[hidden email]> wrote:

> Hi Krzysztof,
>
> The reason is that in C++03 make_pair looked like this
>
>     template <class T1, class T2>
>     pair<T1, T2> make_pair(T1 x, T2 y);
>
> while in C++11 onwards looks like this
>
>      template <class T1, class T2>
>      pair<V1, V2> make_pair(T1&& x, T2&& y)
>
> where in libcxx (similarly for libstdc++) V1 and V2 are implemented like
>
>      pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
>
> because the C++ standard dictates a more sophisticated (compile-time computed) type for V1 and V2.
>
> This implies that if you define T1 and T2 in the template-argument list of the function call, you are always going to get rvalue references in the parameter types (in your example 'int&&' and 'unsigned int&&' respectively).
> Conversely, if you let template-argument deduction to infer T1 and T2, it will infer
>
>   std::pair<int, unsigned int> std::make_pair<int, unsigned int &>(int &&, unsigned int &);
>
> because of the C++11 rules about type deduction involving parameter types of the form Type&&.
>
> I'm not an expert in this area but this behaviour looks to me as expected and matches the C++ view of generic programming in which you should not constraint (in this case using template-arguments) if not needed.
>
> Hope this answers your question.
>
> Kind regards,
> Roger
>
>> -----Original Message-----
>> From: cfe-dev [mailto:[hidden email]] On Behalf Of
>> Krzysztof Parzyszek via cfe-dev
>> Sent: 16 November 2017 17:21
>> To: Clang Dev
>> Subject: [cfe-dev] Explicit template arguments in std::make_pair
>>
>> Hi,
>>
>> This simple program fails to compile with -std=c++11, but compiles ok
>> with c++03. This seems consistent between libc++/libstdc++. Is this due
>> to a change in the standard? What is the reason behind it?
>>
>>
>>
>> #include <utility>
>>
>> std::pair<int,unsigned> good(unsigned L) {
>>    return std::make_pair(0, L);
>> }
>>
>> std::pair<int,unsigned> bad(unsigned L) {
>>    return std::make_pair<int,unsigned>(0, L);
>> }
>>
>>
>> clang++ -c -std=c++11 pp.cpp -stdlib=libc++
>> pp.cpp:8:10: error: no matching function for call to 'make_pair'
>>    return std::make_pair<int,unsigned>(0, L);
>>           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> /w/c/org/bin/../include/c++/v1/utility:639:1: note: candidate function not
>>        viable: no known conversion from 'unsigned int' to 'unsigned int
>> &&' for
>>        2nd argument
>> make_pair(_T1&& __t1, _T2&& __t2)
>> ^
>> 1 error generated.
>>
>>
>> -Krzysztof
>>
>> --
>> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
>> hosted by The Linux Foundation
>> _______________________________________________
>> cfe-dev mailing list
>> [hidden email]
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
> _______________________________________________
> cfe-dev mailing list
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



--
GCS a+ e++ d- C++ ULS$ L+$ !E- W++ P+++$ w++$ tv+ b++ DI D++ 5++
The Tao of math: The numbers you can count are not the real numbers.
Life is complex, with real and imaginary parts.
"Ok, it boots. Which means it must be bug-free and perfect. " -- Linus Torvalds
"People disagree with me. I just ignore them." -- Linus Torvalds
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev
In reply to this post by Boris Kolpackov via cfe-dev
> On Nov 16, 2017, at 12:39 PM, Roger Ferrer Ibanez via cfe-dev <[hidden email]> wrote:
> Hi Krzysztof,
>
> The reason is that in C++03 make_pair looked like this
>
>    template <class T1, class T2>
>    pair<T1, T2> make_pair(T1 x, T2 y);
>
> while in C++11 onwards looks like this
>
>     template <class T1, class T2>
>     pair<V1, V2> make_pair(T1&& x, T2&& y)
>
> where in libcxx (similarly for libstdc++) V1 and V2 are implemented like
>
>     pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
>
> because the C++ standard dictates a more sophisticated (compile-time computed) type for V1 and V2.
>
> This implies that if you define T1 and T2 in the template-argument list of the function call, you are always going to get rvalue references in the parameter types (in your example 'int&&' and 'unsigned int&&' respectively).
> Conversely, if you let template-argument deduction to infer T1 and T2, it will infer
>
>  std::pair<int, unsigned int> std::make_pair<int, unsigned int &>(int &&, unsigned int &);
>
> because of the C++11 rules about type deduction involving parameter types of the form Type&&.
>
> I'm not an expert in this area but this behaviour looks to me as expected and matches the C++ view of generic programming in which you should not constraint (in this case using template-arguments) if not needed.

More generally, the C++ standard library guarantees that specific expression forms will compile and have certain static and dynamic properties.  If there isn't a listed expression form with explicit template arguments, they're not portably allowed, and including them means you're exceeding the guarantees of the standard library just as much as you would be if you tried to forward-declare std::basic_string, or took the address of std::sort, or spelled out a concrete result type for std::vector<bool>::operator[].

John.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev
Thanks all, that explains it.

I do provide explicit arguments sometimes when the object types aren't
quite what I want the compiler to use, for example:
   int x;
   unsigned y;
   std::make_pair<int,int>(x, y)
instead of
   std::make_pair(x, int(y)).

I suppose the latter may be the preferred version in the recent C++.

-Krzysztof


On 11/16/2017 2:34 PM, John McCall wrote:

>> On Nov 16, 2017, at 12:39 PM, Roger Ferrer Ibanez via cfe-dev <[hidden email]> wrote:
>> Hi Krzysztof,
>>
>> The reason is that in C++03 make_pair looked like this
>>
>>     template <class T1, class T2>
>>     pair<T1, T2> make_pair(T1 x, T2 y);
>>
>> while in C++11 onwards looks like this
>>
>>      template <class T1, class T2>
>>      pair<V1, V2> make_pair(T1&& x, T2&& y)
>>
>> where in libcxx (similarly for libstdc++) V1 and V2 are implemented like
>>
>>      pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
>>
>> because the C++ standard dictates a more sophisticated (compile-time computed) type for V1 and V2.
>>
>> This implies that if you define T1 and T2 in the template-argument list of the function call, you are always going to get rvalue references in the parameter types (in your example 'int&&' and 'unsigned int&&' respectively).
>> Conversely, if you let template-argument deduction to infer T1 and T2, it will infer
>>
>>   std::pair<int, unsigned int> std::make_pair<int, unsigned int &>(int &&, unsigned int &);
>>
>> because of the C++11 rules about type deduction involving parameter types of the form Type&&.
>>
>> I'm not an expert in this area but this behaviour looks to me as expected and matches the C++ view of generic programming in which you should not constraint (in this case using template-arguments) if not needed.
>
> More generally, the C++ standard library guarantees that specific expression forms will compile and have certain static and dynamic properties.  If there isn't a listed expression form with explicit template arguments, they're not portably allowed, and including them means you're exceeding the guarantees of the standard library just as much as you would be if you tried to forward-declare std::basic_string, or took the address of std::sort, or spelled out a concrete result type for std::vector<bool>::operator[].
>
> John.
>

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Explicit template arguments in std::make_pair

Boris Kolpackov via cfe-dev

> On Nov 16, 2017, at 5:38 PM, Krzysztof Parzyszek <[hidden email]> wrote:
>
> Thanks all, that explains it.
>
> I do provide explicit arguments sometimes when the object types aren't quite what I want the compiler to use, for example:
>  int x;
>  unsigned y;
>  std::make_pair<int,int>(x, y)
> instead of
>  std::make_pair(x, int(y)).
>
> I suppose the latter may be the preferred version in the recent C++.

You can also just use std::pair<int,int>(x,y) if you're going to declare both arguments.

John.

>
> -Krzysztof
>
>
> On 11/16/2017 2:34 PM, John McCall wrote:
>>> On Nov 16, 2017, at 12:39 PM, Roger Ferrer Ibanez via cfe-dev <[hidden email]> wrote:
>>> Hi Krzysztof,
>>>
>>> The reason is that in C++03 make_pair looked like this
>>>
>>>    template <class T1, class T2>
>>>    pair<T1, T2> make_pair(T1 x, T2 y);
>>>
>>> while in C++11 onwards looks like this
>>>
>>>     template <class T1, class T2>
>>>     pair<V1, V2> make_pair(T1&& x, T2&& y)
>>>
>>> where in libcxx (similarly for libstdc++) V1 and V2 are implemented like
>>>
>>>     pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
>>>
>>> because the C++ standard dictates a more sophisticated (compile-time computed) type for V1 and V2.
>>>
>>> This implies that if you define T1 and T2 in the template-argument list of the function call, you are always going to get rvalue references in the parameter types (in your example 'int&&' and 'unsigned int&&' respectively).
>>> Conversely, if you let template-argument deduction to infer T1 and T2, it will infer
>>>
>>>  std::pair<int, unsigned int> std::make_pair<int, unsigned int &>(int &&, unsigned int &);
>>>
>>> because of the C++11 rules about type deduction involving parameter types of the form Type&&.
>>>
>>> I'm not an expert in this area but this behaviour looks to me as expected and matches the C++ view of generic programming in which you should not constraint (in this case using template-arguments) if not needed.
>> More generally, the C++ standard library guarantees that specific expression forms will compile and have certain static and dynamic properties.  If there isn't a listed expression form with explicit template arguments, they're not portably allowed, and including them means you're exceeding the guarantees of the standard library just as much as you would be if you tried to forward-declare std::basic_string, or took the address of std::sort, or spelled out a concrete result type for std::vector<bool>::operator[].
>> John.
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev