Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #68215 > unrolled thread
| Started by | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| First post | 2019-09-04 13:55 +0000 |
| Last post | 2019-09-07 18:35 -0400 |
| Articles | 13 — 6 participants |
Back to article view | Back to comp.lang.c++
Template argument deduction mystery Juha Nieminen <nospam@thanks.invalid> - 2019-09-04 13:55 +0000
Re: Template argument deduction mystery Ian Collins <ian-news@hotmail.com> - 2019-09-05 07:16 +1200
Re: Template argument deduction mystery Bonita Montero <Bonita.Montero@gmail.com> - 2019-09-05 03:03 +0200
Re: Template argument deduction mystery Juha Nieminen <nospam@thanks.invalid> - 2019-09-05 21:50 +0000
Re: Template argument deduction mystery Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-05 20:04 -0400
Re: Template argument deduction mystery Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-09-06 14:55 +0100
Re: Template argument deduction mystery Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-06 23:56 -0400
Re: Template argument deduction mystery Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-09-07 15:25 +0100
Re: Template argument deduction mystery Juha Nieminen <nospam@thanks.invalid> - 2019-09-07 18:55 +0000
Re: Template argument deduction mystery Bo Persson <bo@bo-persson.se> - 2019-09-07 21:28 +0200
Re: Template argument deduction mystery Ian Collins <ian-news@hotmail.com> - 2019-09-08 12:29 +1200
Re: Template argument deduction mystery Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2019-09-07 23:06 +0100
Re: Template argument deduction mystery Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> - 2019-09-07 18:35 -0400
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2019-09-04 13:55 +0000 |
| Subject | Template argument deduction mystery |
| Message-ID | <qkofo9$9mo$1@adenine.netfront.net> |
In C++17 you can do this:
//-----------------------------------------------------
#include <iostream>
#include <algorithm>
#include <functional>
int main(int argc, char** argv)
{
double values[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
// Notice this:
std::sort(values, values+5, std::greater());
for(double v: values) std::cout << v << " ";
std::cout << "\n";
}
//-----------------------------------------------------
You don't actually need to specify the template parameter of std::greater.
It will be automatically deduced as 'double'. That's really nice.
But wait... How?!?
There's nothing telling std::greater that the template parameter should be
of type double. It's not taking any constructor parameters or anything.
And the declaration of std::sort() is ostensibly like this:
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);
so there's nothing there telling it that it should be double either.
So how?
[toc] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2019-09-05 07:16 +1200 |
| Message-ID | <gtagsnFnafoU3@mid.individual.net> |
| In reply to | #68215 |
On 05/09/2019 01:55, Juha Nieminen wrote:
> In C++17 you can do this:
>
> //-----------------------------------------------------
> #include <iostream>
> #include <algorithm>
> #include <functional>
>
> int main(int argc, char** argv)
> {
> double values[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
>
> // Notice this:
> std::sort(values, values+5, std::greater());
>
> for(double v: values) std::cout << v << " ";
> std::cout << "\n";
> }
> //-----------------------------------------------------
>
> You don't actually need to specify the template parameter of std::greater.
> It will be automatically deduced as 'double'. That's really nice.
>
> But wait... How?!?
>
> There's nothing telling std::greater that the template parameter should be
> of type double. It's not taking any constructor parameters or anything.
> And the declaration of std::sort() is ostensibly like this:
>
> template<class RandomIt, class Compare>
> void sort(RandomIt first, RandomIt last, Compare comp);
>
> so there's nothing there telling it that it should be double either.
>
> So how?
Magic? I assume it's related to the changes in C++17 which extend
template argument deduction to template classes as well as functions.
All of the information is there, given the signature of Compare is bool
comp(const Type1 &a, const Type2 &b) and Type1 and Type2 can be deduced
from RandomIt.
--
Ian.
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2019-09-05 03:03 +0200 |
| Message-ID | <qkpmsb$v9r$1@news.albasani.net> |
| In reply to | #68215 |
> std::sort(values, values+5, std::greater()); Doesn't work for me. As I excpected VC++ as well as g++ require a template parameter.
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2019-09-05 21:50 +0000 |
| Message-ID | <qkrvui$22o2$1@adenine.netfront.net> |
| In reply to | #68223 |
Bonita Montero <Bonita.Montero@gmail.com> wrote: >> std::sort(values, values+5, std::greater()); > > Doesn't work for me. > As I excpected VC++ as well as g++ require a template parameter. It appears that gcc has been slow to implement automatic template parameter deduction of this caliber. It only works from gcc 9 forwards. It doesn't work on previous versions of gcc. It does work on the current version of clang (I haven't tested which is the first version that added support). As for the answer to the question, I think I understand it now. std::greater is currently declared as template<typename T=void> struct greater; This means that the C++17 automatic template parameter deduction will make it std::greater<void> when no parameter is specified. std::greater<void> in turn has a specialization that has a templated operator(), which allows it to compare any types.
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-05 20:04 -0400 |
| Message-ID | <rohcF.533208$on8.458387@fx46.iad> |
| In reply to | #68243 |
Juha Nieminen wrote: > Bonita Montero <Bonita.Montero@gmail.com> wrote: >>> std::sort(values, values+5, std::greater()); >> >> Doesn't work for me. >> As I excpected VC++ as well as g++ require a template parameter. > > It appears that gcc has been slow to implement automatic template > parameter deduction of this caliber. It only works from gcc 9 > forwards. It doesn't work on previous versions of gcc. > > It does work on the current version of clang (I haven't tested > which is the first version that added support). > > As for the answer to the question, I think I understand it now. > > std::greater is currently declared as > > template<typename T=void> > struct greater; > > This means that the C++17 automatic template parameter deduction > will make it std::greater<void> when no parameter is specified. > > std::greater<void> in turn has a specialization that has a > templated operator(), which allows it to compare any types. > Uh-huh. Just in case you have not found it these are called "deduction guides" in the standard. I did not answer you question because I still don't understand these enough to use fearlessly. A good tutorial / how-to article would be useful. -Pavel
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-09-06 14:55 +0100 |
| Message-ID | <20190906145510.4c03182d29e071b060cb8ad9@cvine--nospam--.freeserve.co.uk> |
| In reply to | #68245 |
On Thu, 5 Sep 2019 20:04:39 -0400 Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: > Juha Nieminen wrote: > > Bonita Montero <Bonita.Montero@gmail.com> wrote: > >>> std::sort(values, values+5, std::greater()); > >> > >> Doesn't work for me. > >> As I excpected VC++ as well as g++ require a template parameter. > > > > It appears that gcc has been slow to implement automatic template > > parameter deduction of this caliber. It only works from gcc 9 > > forwards. It doesn't work on previous versions of gcc. > > > > It does work on the current version of clang (I haven't tested > > which is the first version that added support). > > > > As for the answer to the question, I think I understand it now. > > > > std::greater is currently declared as > > > > template<typename T=void> > > struct greater; > > > > This means that the C++17 automatic template parameter deduction > > will make it std::greater<void> when no parameter is specified. > > > > std::greater<void> in turn has a specialization that has a > > templated operator(), which allows it to compare any types. > > > Uh-huh. Just in case you have not found it these are called "deduction > guides" in the standard. I did not answer you question because I still > don't understand these enough to use fearlessly. A good tutorial / > how-to article would be useful. -Pavel 'template <typename T = void> struct greater' (and its equivalent for the other standard comparison structs) was first provided in C++14 (not C++17), allowing type deduction for operator(). It does not need to rely on C++17 deduction guides - you can supply an empty template type specifier of <> when instantiating std::greater in C++14.
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-06 23:56 -0400 |
| Message-ID | <OTFcF.511763$tG2.425205@fx48.iad> |
| In reply to | #68260 |
Chris Vine wrote: > On Thu, 5 Sep 2019 20:04:39 -0400 > Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: >> Juha Nieminen wrote: >>> Bonita Montero <Bonita.Montero@gmail.com> wrote: >>>>> std::sort(values, values+5, std::greater()); >>>> >>>> Doesn't work for me. >>>> As I excpected VC++ as well as g++ require a template parameter. >>> >>> It appears that gcc has been slow to implement automatic template >>> parameter deduction of this caliber. It only works from gcc 9 >>> forwards. It doesn't work on previous versions of gcc. >>> >>> It does work on the current version of clang (I haven't tested >>> which is the first version that added support). >>> >>> As for the answer to the question, I think I understand it now. >>> >>> std::greater is currently declared as >>> >>> template<typename T=void> >>> struct greater; >>> >>> This means that the C++17 automatic template parameter deduction >>> will make it std::greater<void> when no parameter is specified. >>> >>> std::greater<void> in turn has a specialization that has a >>> templated operator(), which allows it to compare any types. >>> >> Uh-huh. Just in case you have not found it these are called "deduction >> guides" in the standard. I did not answer you question because I still >> don't understand these enough to use fearlessly. A good tutorial / >> how-to article would be useful. -Pavel > > 'template <typename T = void> struct greater' (and its equivalent for > the other standard comparison structs) was first provided in C++14 > (not C++17), allowing type deduction for operator(). It does not need > to rely on C++17 deduction guides - you can supply an empty template > type specifier of <> when instantiating std::greater in C++14. OP asked how std::greater() works (i.e. w/o <>). I think for this to work, guides are needed, no? -Pavel
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-09-07 15:25 +0100 |
| Message-ID | <20190907152518.13d08d857bf2360dcd972522@cvine--nospam--.freeserve.co.uk> |
| In reply to | #68264 |
On Fri, 6 Sep 2019 23:56:30 -0400 Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: > Chris Vine wrote: > > On Thu, 5 Sep 2019 20:04:39 -0400 > > Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: > >> Juha Nieminen wrote: > >>> Bonita Montero <Bonita.Montero@gmail.com> wrote: > >>>>> std::sort(values, values+5, std::greater()); > >>>> > >>>> Doesn't work for me. > >>>> As I excpected VC++ as well as g++ require a template parameter. > >>> > >>> It appears that gcc has been slow to implement automatic template > >>> parameter deduction of this caliber. It only works from gcc 9 > >>> forwards. It doesn't work on previous versions of gcc. > >>> > >>> It does work on the current version of clang (I haven't tested > >>> which is the first version that added support). > >>> > >>> As for the answer to the question, I think I understand it now. > >>> > >>> std::greater is currently declared as > >>> > >>> template<typename T=void> > >>> struct greater; > >>> > >>> This means that the C++17 automatic template parameter deduction > >>> will make it std::greater<void> when no parameter is specified. > >>> > >>> std::greater<void> in turn has a specialization that has a > >>> templated operator(), which allows it to compare any types. > >>> > >> Uh-huh. Just in case you have not found it these are called "deduction > >> guides" in the standard. I did not answer you question because I still > >> don't understand these enough to use fearlessly. A good tutorial / > >> how-to article would be useful. -Pavel > > > > 'template <typename T = void> struct greater' (and its equivalent for > > the other standard comparison structs) was first provided in C++14 > > (not C++17), allowing type deduction for operator(). It does not neeld > > to rely on C++17 deduction guides - you can supply an empty template > > type specifier of <> when instantiating std::greater in C++14. > > work, guides are needed, no? -Pavel As I read it, he asked about the specialization of std::greater<void> which allows type deduction in its call operator. That was made available in C++14. In any event, although I am willing to be corrected I thought deduction guides were only relevant to constructors, and the constructor of std::greater takes no arguments from which types can be deduced. It is the call operator which carries out type deduction where the std::greater type is instantiated (explicitly or implicitly) for the void type. C++17 happens (as I understand it) to allow the <> to be omitted where the object is instantiated for the default type.
[toc] | [prev] | [next] | [standalone]
| From | Juha Nieminen <nospam@thanks.invalid> |
|---|---|
| Date | 2019-09-07 18:55 +0000 |
| Message-ID | <ql0ufs$1pup$1@adenine.netfront.net> |
| In reply to | #68267 |
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote: > As I read it, he asked about the specialization of std::greater<void> > which allows type deduction in its call operator. That was made > available in C++14. I was, in fact, asking about both things. It was completely mysterious to me how exactly std::greater would know that it was supposed to be comparing doubles, when nowhere in its instantiation it's told that. I didn't know that it has a specialization for void that works for exactly this kind of situation. It's also a bit unclear to me how it works without the empty <> brackets. I know it's related to C++ automatic template type deduction, but it's unclear to me how it works in this case. Curiously, it appears that it works without any explicit deduction guides. It works for the mere reason that the default template parameter for std::greater is void. The rules of automatic template parameter type deduction are still a bit unclear to me.
[toc] | [prev] | [next] | [standalone]
| From | Bo Persson <bo@bo-persson.se> |
|---|---|
| Date | 2019-09-07 21:28 +0200 |
| Message-ID | <gtiemvFoelvU1@mid.individual.net> |
| In reply to | #68272 |
On 2019-09-07 at 20:55, Juha Nieminen wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>> As I read it, he asked about the specialization of std::greater<void>
>> which allows type deduction in its call operator. That was made
>> available in C++14.
>
> I was, in fact, asking about both things.
>
> It was completely mysterious to me how exactly std::greater would
> know that it was supposed to be comparing doubles, when nowhere in
> its instantiation it's told that. I didn't know that it has a
> specialization for void that works for exactly this kind of situation.
>
> It's also a bit unclear to me how it works without the empty <>
> brackets. I know it's related to C++ automatic template type
> deduction, but it's unclear to me how it works in this case.
> Curiously, it appears that it works without any explicit deduction
> guides. It works for the mere reason that the default template
> parameter for std::greater is void.
>
> The rules of automatic template parameter type deduction are still
> a bit unclear to me.
>
The possiblity of omitting an empty <> is just mentioned in passing,
while decribing "Explicit template argument specification":
"Trailing template arguments that can be deduced or obtained from
default template-arguments may be omitted from the list of explicit
template-arguments. A trailing template parameter pack ([temp.variadic])
not otherwise deduced will be deduced as an empty sequence of template
arguments. If all of the template arguments can be deduced, they may all
be omitted; in this case, **the empty template argument list <> itself
may also be omitted.**"
http://eel.is/c++draft/temp.arg.explicit#4
Not obvious at all, if you happened to skip over the last part of this
sentence. :-)
Bo Persson
[toc] | [prev] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2019-09-08 12:29 +1200 |
| Message-ID | <gtj0bpFnafoU5@mid.individual.net> |
| In reply to | #68273 |
On 08/09/2019 07:28, Bo Persson wrote: > On 2019-09-07 at 20:55, Juha Nieminen wrote: >> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote: >>> As I read it, he asked about the specialization of std::greater<void> >>> which allows type deduction in its call operator. That was made >>> available in C++14. >> >> I was, in fact, asking about both things. >> >> It was completely mysterious to me how exactly std::greater would >> know that it was supposed to be comparing doubles, when nowhere in >> its instantiation it's told that. I didn't know that it has a >> specialization for void that works for exactly this kind of situation. >> >> It's also a bit unclear to me how it works without the empty <> >> brackets. I know it's related to C++ automatic template type >> deduction, but it's unclear to me how it works in this case. >> Curiously, it appears that it works without any explicit deduction >> guides. It works for the mere reason that the default template >> parameter for std::greater is void. >> >> The rules of automatic template parameter type deduction are still >> a bit unclear to me. >> > > The possiblity of omitting an empty <> is just mentioned in passing, > while decribing "Explicit template argument specification": > > "Trailing template arguments that can be deduced or obtained from > default template-arguments may be omitted from the list of explicit > template-arguments. A trailing template parameter pack ([temp.variadic]) > not otherwise deduced will be deduced as an empty sequence of template > arguments. If all of the template arguments can be deduced, they may all > be omitted; in this case, **the empty template argument list <> itself > may also be omitted.**" > > http://eel.is/c++draft/temp.arg.explicit#4 > > > Not obvious at all, if you happened to skip over the last part of this > sentence. :-) Thanks for filling in the gaps and the link! I glad I'm not a compiler writer... gcc-9 gets it right, gcc-8 gets it wrong. -- Ian.
[toc] | [prev] | [next] | [standalone]
| From | Chris Vine <chris@cvine--nospam--.freeserve.co.uk> |
|---|---|
| Date | 2019-09-07 23:06 +0100 |
| Message-ID | <20190907230626.a1cd5d7a1c2e29cd886e0edc@cvine--nospam--.freeserve.co.uk> |
| In reply to | #68272 |
On Sat, 7 Sep 2019 18:55:59 -0000 (UTC)
Juha Nieminen <nospam@thanks.invalid> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
> > As I read it, he asked about the specialization of std::greater<void>
> > which allows type deduction in its call operator. That was made
> > available in C++14.
>
> I was, in fact, asking about both things.
>
> It was completely mysterious to me how exactly std::greater would
> know that it was supposed to be comparing doubles, when nowhere in
> its instantiation it's told that. I didn't know that it has a
> specialization for void that works for exactly this kind of situation.
>
> It's also a bit unclear to me how it works without the empty <>
> brackets. I know it's related to C++ automatic template type
> deduction, but it's unclear to me how it works in this case.
> Curiously, it appears that it works without any explicit deduction
> guides. It works for the mere reason that the default template
> parameter for std::greater is void.
>
> The rules of automatic template parameter type deduction are still
> a bit unclear to me.
For instantiations of std::greater for other than the void type, the
call operator takes arguments of the type for which the struct has been
instantiated. In particular, std::greater is a class template, but the
call operator is not a function template so no type deduction takes
place.
std::greater<void> is a specialization of std::greater. In this
specialization, the call operator is a function template. So it does
deduce the type.
If this is still confusing note that:
template <class T> struct A { // class template
void do_it(T) {...} // not a function template, no deduction
};
struct B {
template <class T>
void do_it(T) {...} // function template, argument types deduced
};
[toc] | [prev] | [next] | [standalone]
| From | Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> |
|---|---|
| Date | 2019-09-07 18:35 -0400 |
| Message-ID | <bhWcF.187745$9Z1.164763@fx41.iad> |
| In reply to | #68267 |
Chris Vine wrote: > On Fri, 6 Sep 2019 23:56:30 -0400 > Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: >> Chris Vine wrote: >>> On Thu, 5 Sep 2019 20:04:39 -0400 >>> Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo> wrote: >>>> Juha Nieminen wrote: >>>>> Bonita Montero <Bonita.Montero@gmail.com> wrote: >>>>>>> std::sort(values, values+5, std::greater()); >>>>>> >>>>>> Doesn't work for me. >>>>>> As I excpected VC++ as well as g++ require a template parameter. >>>>> >>>>> It appears that gcc has been slow to implement automatic template >>>>> parameter deduction of this caliber. It only works from gcc 9 >>>>> forwards. It doesn't work on previous versions of gcc. >>>>> >>>>> It does work on the current version of clang (I haven't tested >>>>> which is the first version that added support). >>>>> >>>>> As for the answer to the question, I think I understand it now. >>>>> >>>>> std::greater is currently declared as >>>>> >>>>> template<typename T=void> >>>>> struct greater; >>>>> >>>>> This means that the C++17 automatic template parameter deduction >>>>> will make it std::greater<void> when no parameter is specified. >>>>> >>>>> std::greater<void> in turn has a specialization that has a >>>>> templated operator(), which allows it to compare any types. >>>>> >>>> Uh-huh. Just in case you have not found it these are called "deduction >>>> guides" in the standard. I did not answer you question because I still >>>> don't understand these enough to use fearlessly. A good tutorial / >>>> how-to article would be useful. -Pavel >>> >>> 'template <typename T = void> struct greater' (and its equivalent for >>> the other standard comparison structs) was first provided in C++14 >>> (not C++17), allowing type deduction for operator(). It does not neeld >>> to rely on C++17 deduction guides - you can supply an empty template >>> type specifier of <> when instantiating std::greater in C++14. >> >> work, guides are needed, no? -Pavel > > As I read it, he asked about the specialization of std::greater<void> > which allows type deduction in its call operator. That was made > available in C++14. > > In any event, although I am willing to be corrected I thought > deduction guides were only relevant to constructors, and the > constructor of std::greater takes no arguments from which types can be > deduced. It is the call operator which carries out type deduction > where the std::greater type is instantiated (explicitly or implicitly) > for the void type. C++17 happens (as I understand it) to allow the <> > to be omitted where the object is instantiated for the default type. > Thanks, good to know; always glad to stand corrected. As I mentioned, I did not yet understand the guides enough so I guess I was ascribing all superpowers to them. Turned out, the explanation was much simpler: the syntax with <> could even be implemented at C++11 level if defined for the library. -Pavel
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web