Does template deduction for constructors solve the array size deduction problem?

141 views
Skip to first unread message

Nicol Bolas

unread,
Jul 26, 2016, 7:59:08 PM7/26/16
to ISO C++ Standard - Future Proposals
Template deduction for constructors allows us to declare a deduction guide that maps from potential usage to the actual template type. These deduction guides do not prevent a type from being an aggregate. So with a guide, this will work:


template<typename T1, typename T2>
struct new_pair
{
  T1 t1
;
  T2 t2
;
};

template<typename T1, typename T2>
new_pair
(T1, T2) -> new_pair<T1, T2>;

new_pair
{12.3f, 90}; //T1 = float, T2 = int.

Does that mean that it is possible to make this work with `std::array`:

auto arr = std::array{2, 3, 1, 4, 44, 23}; //type is deduced as int, size is deduced as 6.

I'm thinking of a guide like this:

template<typename T>
std
::array(T ...ts) -> std::array<T, sizeof...(ts);

Or if not that, what about:

template<typename Ts...>
std
::array(Ts ...ts) -> std::array<std::common_type_t<T...>, sizeof...(ts)>;

If the current syntax doesn't allow a way to deduce the number of parameters... is there a way to make it work with some small change to the functionality?

Faisal Vali

unread,
Jul 26, 2016, 8:56:00 PM7/26/16
to <std-proposals@isocpp.org>
On Tue, Jul 26, 2016 at 6:59 PM, Nicol Bolas <jmck...@gmail.com> wrote:
> Template deduction for constructors allows us to declare a deduction guide
> that maps from potential usage to the actual template type. These deduction
> guides do not prevent a type from being an aggregate. So with a guide, this
> will work:
>
>
> template<typename T1, typename T2>
> struct new_pair
> {
> T1 t1;
> T2 t2;
> };
>
> template<typename T1, typename T2>
> new_pair(T1, T2) -> new_pair<T1, T2>;
>
> new_pair{12.3f, 90}; //T1 = float, T2 = int.
>

Yes.

> Does that mean that it is possible to make this work with `std::array`:
>

Yes.

> auto arr = std::array{2, 3, 1, 4, 44, 23}; //type is deduced as int, size is
> deduced as 6.
>
> I'm thinking of a guide like this:
>
> template<typename T>
> std::array(T ...ts) -> std::array<T, sizeof...(ts);
>

> Or if not that, what about:
>
> template<typename Ts...>
> std::array(Ts ...ts) -> std::array<std::common_type_t<T...>, sizeof...(ts)>;
>

Yes, that should work (modulo syntax bug regarding ellipsis placement
in your template parameter pack).


> If the current syntax doesn't allow a way to deduce the number of
> parameters... is there a way to make it work with some small change to the
> functionality?
>
> --
> 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/7db3740d-f9cf-45ad-a8c6-c61c3b1f9e8f%40isocpp.org.

Edward Catmur

unread,
Jul 26, 2016, 8:59:32 PM7/26/16
to ISO C++ Standard - Future Proposals
On Wednesday, 27 July 2016 00:59:08 UTC+1, Nicol Bolas wrote:
Template deduction for constructors allows us to declare a deduction guide that maps from potential usage to the actual template type. These deduction guides do not prevent a type from being an aggregate. [...]

For reference, the proposal series is denoted P0091 and the most recent paper is Template argument deduction for class templates (Rev. 6)[1].
 
Does that mean that it is possible to make this work with `std::array`:

auto arr = std::array{2, 3, 1, 4, 44, 23}; //type is deduced as int, size is deduced as 6.

Yes.

I'm thinking of a guide like this:

template<typename T>
std
::array(T ...ts) -> std::array<T, sizeof...(ts);
 
The parameter-declaration-clause in a deduction guide is subject to the same restrictions as a function declaration. You couldn't declare a function as template<typename T> make_array(T... ts) -> std::array<T, sizeof...(ts)>, so likewise you can't declare a deduction guide with that parameter-declaration-clause.
 
Or if not that, what about:

template<typename Ts...>
std
::array(Ts ...ts) -> std::array<std::common_type_t<T...>, sizeof...(ts)>;

Now we're talking. This is nearly correct; aside from one or two typos, the only issue is that the guide must be declared in the same scope as the template i.e. within namespace std. (I'm pretty sure reopening namespace std is allowed; it'd be odd if it wasn't.)

Again, think of deduction guides as shorthand make_XXX functions: the function template template<class... Ts> make_array(Ts...) -> array<common_type_t<Ts...>, sizeof...(Ts)> is already a member of the standard, so adding the corresponding deduction guide should be a matter of course.

Faisal Vali

unread,
Jul 26, 2016, 9:08:08 PM7/26/16
to <std-proposals@isocpp.org>
You can add specializations to namespace std - and you should be able
to add deduction guides too (I hope the wording reflects that).


> Again, think of deduction guides as shorthand make_XXX functions: the
> function template template<class... Ts> make_array(Ts...) ->
> array<common_type_t<Ts...>, sizeof...(Ts)> is already a member of the
> standard, so adding the corresponding deduction guide should be a matter of
> course.
>
> 1. http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0091r3.html
>
> --
> 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/09b1e9a6-afb0-4463-83b6-d349b000f516%40isocpp.org.

Nicol Bolas

unread,
Jul 26, 2016, 10:34:06 PM7/26/16
to ISO C++ Standard - Future Proposals
On Tuesday, July 26, 2016 at 8:59:32 PM UTC-4, Edward Catmur wrote:
On Wednesday, 27 July 2016 00:59:08 UTC+1, Nicol Bolas wrote:
Template deduction for constructors allows us to declare a deduction guide that maps from potential usage to the actual template type. These deduction guides do not prevent a type from being an aggregate. [...]

For reference, the proposal series is denoted P0091 and the most recent paper is Template argument deduction for class templates (Rev. 6)[1].
 
Does that mean that it is possible to make this work with `std::array`:

auto arr = std::array{2, 3, 1, 4, 44, 23}; //type is deduced as int, size is deduced as 6.

Yes.

I'm thinking of a guide like this:

template<typename T>
std
::array(T ...ts) -> std::array<T, sizeof...(ts);
 
The parameter-declaration-clause in a deduction guide is subject to the same restrictions as a function declaration. You couldn't declare a function as template<typename T> make_array(T... ts) -> std::array<T, sizeof...(ts)>, so likewise you can't declare a deduction guide with that parameter-declaration-clause.
 
Or if not that, what about:

template<typename Ts...>
std
::array(Ts ...ts) -> std::array<std::common_type_t<T...>, sizeof...(ts)>;

Now we're talking. This is nearly correct; aside from one or two typos, the only issue is that the guide must be declared in the same scope as the template i.e. within namespace std.

So... is that guide going to be part of the standard library? Perhaps a national body comment could get it in?

However, it does raise an interesting limitation. Namely that this would be subject to the limits that compilers have on parameter packs. It's not uncommon to do something like this:

SomeType varname[] =
{
//Table of several thousand entries
};

It seems that such a table would easily blow past the compiler's limits on the number of elements in a pack. It would be so wonderful if there were a way to avoid having to rely on template packs to count the elements in a braced-init-list and feed it to a template parameter.

Edward Catmur

unread,
Jul 27, 2016, 7:29:40 AM7/27/16
to ISO C++ Standard - Future Proposals
A const array reference argument (of form T const (&)[N]) can be deduced from a braced-init-list, so hopefully the following guide should work, possibly with an extra level of braces (although brace elision is so magical that I really couldn't say):

template<class T, unsigned N> auto array(T const (&)[N]) -> array<T, N>;

Annoyingly, this is almost to_array[1] (in the library fundamentals TS v2) but not quite, since to_array lacks the const qualifier so cannot be called with a braced-init-list.

I believe it should be fine for this to overload with the heterogeneous guide above.

Edward Catmur

unread,
Jul 27, 2016, 7:39:14 AM7/27/16
to ISO C++ Standard - Future Proposals
I've opened a thread in std-discussion on the to_array deficiency: https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/GS3j9tcXnI0

Nicol Bolas

unread,
Jul 27, 2016, 10:21:46 AM7/27/16
to ISO C++ Standard - Future Proposals

One more question. Would it be possible to do:

auto variable = array<Typename>{
 
{/*stuff*/},
 
{/*stuff*/},
 
{/*stuff*/},
};

As opposed to:

auto variable = array{
 
Typename{/*stuff*/},
 
Typename{/*stuff*/},
 
Typename{/*stuff*/},
};

Daniel Krügler

unread,
Jul 27, 2016, 10:28:01 AM7/27/16
to std-pr...@isocpp.org
make_array is currently only part of the fundamentals TS v2, not yet
part of the working draft for Standard C++. The most recent proposal
requesting it's upgrade is

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0325r1.html

- Daniel

Edward Catmur

unread,
Jul 27, 2016, 10:38:47 AM7/27/16
to std-pr...@isocpp.org
Sorry, you're right. Thanks for the correction; I'm still getting used to the status of the TSs.

Edward Catmur

unread,
Jul 27, 2016, 10:43:28 AM7/27/16
to std-pr...@isocpp.org
That was removed from the proposal between P0091r2 and P0091r3, following feedback at Oulu (IIRC) that it could lead to unexpected behavior e.g. for tuple<int, char>{42, 'a', 3.141} the user is most likely expecting an error, not a 3-element tuple<int, char, double>.

Perhaps a metafunction might work here; otherwise you could probably cope using to_array and mandatory RVO.

Nicol Bolas

unread,
Jul 27, 2016, 11:18:06 AM7/27/16
to ISO C++ Standard - Future Proposals

`to_array` takes an array as a parameter. You cannot elide the copy from a parameter to an output value.

Edward Catmur

unread,
Jul 27, 2016, 11:32:24 AM7/27/16
to std-pr...@isocpp.org
Guh, sorry. Not thinking straight today. And a metafunction won't work either, since the guide has to operate on a class template directly. All I can think of that would work is inheritance, but it's pretty ugly: 

template<class T> struct array_of {
    template<size_t N> struct type : array<T, N> {};
    template<size_t N> auto type(T const (&)[N]) -> type<N>;
}
auto variable = array_of<Typename>::type{...};


Reply all
Reply to author
Forward
0 new messages