Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #68215 > unrolled thread

Template argument deduction mystery

Started byJuha Nieminen <nospam@thanks.invalid>
First post2019-09-04 13:55 +0000
Last post2019-09-07 18:35 -0400
Articles 13 — 6 participants

Back to article view | Back to comp.lang.c++


Contents

  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

#68215 — Template argument deduction mystery

FromJuha Nieminen <nospam@thanks.invalid>
Date2019-09-04 13:55 +0000
SubjectTemplate 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]


#68221

FromIan Collins <ian-news@hotmail.com>
Date2019-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]


#68223

FromBonita Montero <Bonita.Montero@gmail.com>
Date2019-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]


#68243

FromJuha Nieminen <nospam@thanks.invalid>
Date2019-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]


#68245

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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]


#68260

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2019-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]


#68264

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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]


#68267

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2019-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]


#68272

FromJuha Nieminen <nospam@thanks.invalid>
Date2019-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]


#68273

FromBo Persson <bo@bo-persson.se>
Date2019-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]


#68277

FromIan Collins <ian-news@hotmail.com>
Date2019-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]


#68275

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2019-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]


#68276

FromPavel <pauldontspamtolk@removeyourself.dontspam.yahoo>
Date2019-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