Why is partial class template argument deduction impossible?
Asked Answered
P

2

33

My understanding about the P0091: Template argument deduction for class templates proposal was to homogenize the behavior of function templates and class templates in deduction contexts, but I think that I have misunderstood something.

If we have this class template:

template <std::size_t S, typename T>
struct test
{
    static constexpr auto size = S;
    using type_t = T;

    test(type_t (&input)[size]) : data(input) {}
    type_t (&data)[size]{};
};

I tend to use a helper function as syntactic sugar for creating test objects:

template <std::size_t S, typename T>
test<S, T> helper(T (&input)[S]) { return input; }

Which can be used as shown below:

int buffer[5];

auto a = helper<5, int>(buffer); // No deduction
auto b = helper<5>(buffer);      // Type deduced
auto c = helper(buffer);         // Type and size deduced

The code above compiles. I've tried the same in Wandbox using the newer compiler setup1:

int buffer[5];

test<5, int> a(buffer); // No deduction: OK.
test<5> b(buffer);      // Type deduced: FAILS.
test c(buffer);         // Type and size deduced: OK.

It looks like template argument deduction for class templates works only deducing all the parameters. I was expecting both behaviors (helper function and class template) to be the same; have I misunderstood something?


1The last compilers availables in Wandbox are gcc HEAD 7.0.1 201701 and clang HEAD 5.0.0 (trunk).

Pharmacist answered 24/1, 2017 at 16:40 Comment(4)
Is type_t (&data)[size]{}; an array reference? Is the {} an initializer? Does that compile? Also, sintactic sugar sounds pretty naughty. :)Wassail
Note that adding an explicit deduction guide does not help. I believe that partial deduction is not supported as the standard defines a deduction placeholders in terms of a template name (i.e. with no <...> syntax). Therefore test<5> is not a valid deduction placeholder.Pazpaza
@Muscampester type_t (&data)[size]{}; is an array reference, yes. The {} is indeed the initializer, and it compiles try it out!. About sintactic sugar what can I say... :'( english is not my mother tonghe and I do lots of mistakes!Pharmacist
From what I remember, it was deemed undesirable to have something like tuple<int> t{5, nullptr}; be accepted.Titanic
N
26

From this excellent trip report by Botond Ballo:

The feature as originally proposed included a provision for partial deduction, where you explicitly specify some of the template arguments, and leave the rest to be deduced, but this was pulled over concerns that it can be very confusing in some cases:

// Would have deduced tuple<int, string, float>,
// but tuple<int> is a well-formed type in and of itself!
tuple<int> t(42, "waldo", 2.0f);
Noncompliance answered 25/1, 2017 at 15:2 Comment(4)
I find this reasoning very weird. So first of all we've had std::make_tuple<int> (42, "waldo", 2.0f); doing supposedly the wrong thing all along and taught people that it's wrong to specify template arguments when they are deduced. Now by forbidding this, we make deduction for class template to work in different way as the function one (inconsistency) and block a ton of valid use cases (different from contrived tuple example).Preemie
@Predelnik: The problem is that existing code could use A<T,U> a(t,u,v) with a default template argument for V (or an argument pack of length 2 rather than 3). You dare not silently change such a meaning that depends on what was a perfectly reliable lack of deduction. Maybe if you had only explicit deduction guides, it would be OK, but with the implicit ones it’s too dangerous.Trona
@DavisHerring Yes breaking existing code seems to be a much better reason, it's still sad to not be able to apply it for sane use cases.Preemie
Might consider adding placeholder syntax tuple<int, _, _> t(42, "waldo", 2.0f);Perloff
G
18

There appears to be a contradiction here. Looking at P0091R3, it seems clear that partially specifying parameters is supposed to be allowed:

We propose to allow a template name referring to a class template as a simple-type-specifier or with partially supplied explicit template arguments in two contexts:

But the actual standards wording in the same proposal does not provide a way to handle "partially supplied explicit template arguments". template-name as a simple-type-specifier is not allowed to have template arguments.

So following the specification itself, the compiler's behavior appears to be correct.

Gourami answered 24/1, 2017 at 17:19 Comment(5)
Yes, that paper in particular is a rather egregious case of the author failing to keep the introductory parts in sync as the wording and the design are revised. The result is an actively misleading introductory section, unfortunately.Diglot
Good thing they have another meeting before they want to have the final vote.Poliard
@MikelF: You assume that they will actually allow partial specification. The incongruity in the writing suggests that this was something the committee elected to remove, rather than the original writer simply making a mistake in his wording.Gourami
@NicoBolas What I actually assume (or at least hope) is that they will make it consistent.Poliard
At the very least, it might be worth informing the authors that the current implementation breaks things.Poliard

© 2022 - 2024 — McMap. All rights reserved.