An idea on how to deduce class template arguments from a partial specialization

91 views
Skip to first unread message

Zhihao Yuan

unread,
Oct 31, 2017, 2:19:22 PM10/31/17
to std-pr...@isocpp.org
I was being asked about this question during CppCon,
and I answered "no concrete solution emerged".  Here
is an idea I got recently.

For short, write additional deduction guides like these:

    template <typename T, typename... U>
    array<T>(U...) -> array<T, sizeof...(U)>;

    template <typename... T, typename... U>
    tuple<T...>(T..., U...) -> tuple<T..., U...>;

This syntax looks like function template partial
specializations, but you know there is no such thing.
The semantics is easier to explain if the feature is
also enabled for function templates, where those
extra template arguments here are matched against
"prototype parameters".  Function templates with
prototype parameters are not specializations, just
main templates.  Let's say we have

    template <typename T, typename U>
    auto gcd(T, U);  // 1

    template <typename T, typename U>
    auto gcd<T>(T, U);  // 2

When user calls

    gcd<int>('a', 'b');

, both #1 and #2 participate in overload resolution.  #1
becomes

    gcd<int, char>(int, char);

In #2, first, deduce T out of <int> using the rules of
template argument deduction, then substitute T = int
back into the template and obtain

    gcd<int>(int, U);

, then deduce U out of the type of 'b' which is char, so
it's also

    gcd<int, char>(int, char);

They are equally good, so a disambiguation rule kicks
in and prefers the one substituted from a function
template with prototype parameters.

Deduction guide's version works in the same way.

--
Zhihao Yuan, ID lichray
The best way to predict the future is to invent it.
_______________________________________________

Arthur O'Dwyer

unread,
Oct 31, 2017, 6:31:28 PM10/31/17
to ISO C++ Standard - Future Proposals, z...@miator.net
On Tuesday, October 31, 2017 at 11:19:22 AM UTC-7, Zhihao Yuan wrote:
I was being asked about this question during CppCon,
and I answered "no concrete solution emerged".  Here
is an idea I got recently.

Can you explain the question, please?

When I hear "partial specialization, CTAD, no solution", I immediately think of this fiasco:

    template<class> struct Foo;  // notice the lack of explicit deduction guides

    template<class T>
    struct Foo<T*> {
        Foo(T&);
    };

    int i;
    Foo f(i);  // "obviously" we want Foo<int*>, but in C++17 this is not deducible

Can you explain whether you're trying to solve this problem, or a different problem, and if so, what problem?
Obviously the above problem cannot be "solved" by telling the programmer to write explicit deduction guides, because the problem is that explicit guides are required in the first place.

[...]
Function templates with
prototype parameters are not specializations, just
main templates.  Let's say we have

    template <typename T, typename U>
    auto gcd(T, U);  // 1

    template <typename T, typename U>
    auto gcd<T>(T, U);  // 2

The second of these declarations is a syntax error. Could you rephrase this as valid C++17 code, or else explain what extensions you're assuming?
Incidentally, I don't know what "prototype parameters" means.

–Arthur

Zhihao Yuan

unread,
Oct 31, 2017, 6:58:36 PM10/31/17
to Arthur O'Dwyer, ISO C++ Standard - Future Proposals, Zhihao Yuan
On Tue, Oct 31, 2017 at 5:31 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
Can you explain the question, please?

When I hear "partial specialization, CTAD, no solution", I immediately think of this fiasco:

    template<class> struct Foo;  // notice the lack of explicit deduction guides

    template<class T>
    struct Foo<T*> {

I used a wrong term... What I mean is to deduce from a
_simple-template-id_, like this

  tuple<string> t("str", 1);  // first element std::string

[...]
Function templates with
prototype parameters are not specializations, just
main templates.  Let's say we have

    template <typename T, typename U>
    auto gcd(T, U);  // 1

    template <typename T, typename U>
    auto gcd<T>(T, U);  // 2

The second of these declarations is a syntax error. Could you rephrase this as valid C++17 code, or else explain what extensions you're assuming?
Incidentally, I don't know what "prototype parameters" means.

It's a term used in Concepts TS to mean "the
leading template parameters which can form
currying".  I borrowed this term here in the
description of a new form of function template
I want to propose, whose the syntax is as
same as an "function template partial
specialization", although there is no such thing.

Faisal Vali

unread,
Oct 31, 2017, 8:54:55 PM10/31/17
to <std-proposals@isocpp.org>
On Tue, Oct 31, 2017 at 5:31 PM, Arthur O'Dwyer
<arthur....@gmail.com> wrote:
> On Tuesday, October 31, 2017 at 11:19:22 AM UTC-7, Zhihao Yuan wrote:
>>
>> I was being asked about this question during CppCon,
>> and I answered "no concrete solution emerged". Here
>> is an idea I got recently.
>
>
> Can you explain the question, please?
>
> When I hear "partial specialization, CTAD, no solution", I immediately think
> of this fiasco:
>
> template<class> struct Foo; // notice the lack of explicit deduction
> guides
>
> template<class T>
> struct Foo<T*> {
> Foo(T&);
> };
>
> int i;
> Foo f(i); // "obviously" we want Foo<int*>, but in C++17 this is not
> deducible
>

Why not just iterate through all the partial specializations visible
at the point of deduction - iterating through all their constructors
to generate deduction function templates - and do the same for
explicit specializations (adding non-function templates) - and add
them to all the function templates generated from the primary
template's constructors and deduction-guides. We would need to add
some tie-breakers to the overload resolution process here (such as a
function template from the most specialized specialization (if
orderable) always wins regardless of how specialized it otherwise is,
or only wins if the function-templates are otherwise unorderable -
we'd need to think through this). If we do decide to do something
along these lines - (which I think we should strongly consider
exploring) - I wonder how much backwards compatibility will constrain
us here.

So as a (hopefully) simple example:

template<class T> struct Foo { Foo(T&&); }
template<class T> struct Foo<T*> { Foo(T&); };
template<> struct Foo<int&> { Foo(int&); };

Generates the following notional guides from the above constructors:

template<class T> Foo(T&&) ->Foo<T>; //#1
template<class T> Foo(T&) -> Foo<T*>; // #2
Foo(int&) -> Foo<int&>; //#3

int I;
Foo f{I}; // deduces Foo<int&> from #3

char C;
Foo f2{C}; // deduces Foo<char *> from #2

Foo f3{&C}; // deduce Foo<char *> frfom #1.

Faisal Vali

unread,
Oct 31, 2017, 9:03:46 PM10/31/17
to <std-proposals@isocpp.org>
Oh and following CTAD - the construct will be ill-formed because it
uses the partial specialization whose constructor would reject the
construction.

Arthur O'Dwyer

unread,
Oct 31, 2017, 9:24:04 PM10/31/17
to Zhihao Yuan, ISO C++ Standard - Future Proposals
On Tue, Oct 31, 2017 at 3:58 PM, Zhihao Yuan <z...@miator.net> wrote:
On Tue, Oct 31, 2017 at 5:31 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
Can you explain the question, please?

When I hear "partial specialization, CTAD, no solution", I immediately think of this fiasco:

    template<class> struct Foo;  // notice the lack of explicit deduction guides

    template<class T>
    struct Foo<T*> {

I used a wrong term... What I mean is to deduce from a
_simple-template-id_, like this

  tuple<string> t("str", 1);  // first element std::string

Oh, okay. That seems insane. It's one thing to have "tuple" secretly mean "tuple<string, int>". It's quite another to have "tuple<string>" secretly mean "tuple<string, int>".

–Arthur

Zhihao Yuan

unread,
Oct 31, 2017, 9:37:47 PM10/31/17
to Arthur O'Dwyer, Zhihao Yuan, ISO C++ Standard - Future Proposals
That was the major reason for not doing so
automatically when discussing CTAD for
C++17.  However, if we can specify deduction
guides to match the template argument lists
and place a tiebreaker between the two
kinds of deduction guides, it works safely,
and enables array<int>{ 'a', 'b' }, which may
looks saner for you ;)

Faisal Vali

unread,
Oct 31, 2017, 9:38:44 PM10/31/17
to <std-proposals@isocpp.org>, Zhihao Yuan
On Tue, Oct 31, 2017 at 8:24 PM, Arthur O'Dwyer
<arthur....@gmail.com> wrote:
> On Tue, Oct 31, 2017 at 3:58 PM, Zhihao Yuan <z...@miator.net> wrote:
>>
>> On Tue, Oct 31, 2017 at 5:31 PM, Arthur O'Dwyer
>> <arthur....@gmail.com> wrote:
>>>
>>> Can you explain the question, please?
>>>
>>> When I hear "partial specialization, CTAD, no solution", I immediately
>>> think of this fiasco:
>>>
>>> template<class> struct Foo; // notice the lack of explicit deduction
>>> guides
>>>
>>> template<class T>
>>> struct Foo<T*> {
>>
>>
>> I used a wrong term... What I mean is to deduce from a
>> _simple-template-id_, like this
>>
>> tuple<string> t("str", 1); // first element std::string
>
>
> Oh, okay. That seems insane. It's one thing to have "tuple" secretly mean
> "tuple<string, int>". It's quite another to have "tuple<string>" secretly
> mean "tuple<string, int>".
>

This seems to be a matter of taste. There were some use cases where
it made sense to explicitly specify certain template arguments and
deduce the rest (like we do with some function templates). This
potentially becomes even more useful if we every allow deduction
through template aliases (which would allow us to explicitly specify
arguments such as allocators etc. no matter where they are in the
declaration order). Mike originally intended this to work - but we
pulled it because of some concerns regarding backwards compatibility.

I'm not saying the idea of partial-template-id's is a slam dunk - and
I expect sensible folk to question its justification - but blanketly
labeling it as insane suggests a very narrow (and potentially not v
useful) definition of sanity ;)

> –Arthur
>
> --
> You received this message because you are subscribed to the Google Groups
> "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to std-proposal...@isocpp.org.
> To post to this group, send email to std-pr...@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0L2Sx6XJeH_0vo7eYRTBPe%2BuTSdyZNGa9n7BuMB4DoZgQ%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages