Thanks for the detailed feedback, Vicente. [Comments] below
-----Original Message-----
From: Ext [mailto:ext-b...@lists.isocpp.org] On Behalf Of Vicente J. Botet Escriba
Sent: Saturday, June 4, 2016 8:35 AM
To: Evolution Working Group mailing list <e...@lists.isocpp.org>; C++ Library Evolution Working Group <lib...@lists.isocpp.org>; refle...@isocpp.org
Subject: [Ext] About P0341R0: parameter packs outside of templates
Hi,
thanks Mike for working on this.
Viewing parameter packs as types is a way to introduce anonymous product types in the language and I like this..
* Naming: parameter pack type versus product type
I don't know if using parameter pack type is the good term as this is no
more a parameter.
[Bikeshed. I'm fine either way]
* Parameter pack declarations
I suspect that the easy_tuple constructor should be
template<typename ...U> easy_tuple(U && ...u) : t{u}... {}
Yes.[I assume you are referring to the missing ... in front of U. Yes, that was a typo]
I believe it is worth noting that
T ...t;
wouldn't declare a single member data t, but a pack of them. Anyway,
what will be decltype(t)? I believe that this has no sens and so T...
shouldn't be a type.
I'm not sure you are confirm that it is not a type?[Agreed. Let me know if you saw anything in the paper that suggests otherwise]
* Accessing a template parameter pack outside the template
I believe that there is an error in
return ith_argument<i>(tup....t& ...);
it should be
return ith_argument<i>(tup....t ...);
Yes, but I don't see the need to add &. When you pass an lvalue it converts directly to a reference, isn't it?[Can you elaborate. Don’t we want a reference to the argument?]
The user of ... followed by the . selector is a little noisy and
confusing. Why do we need to use ... to identify that t is is a pack.
What could the meaning of the following?
return ith_argument<i>(tup.t ...);
Ok, we will see if it is needed to disambiguate or not.[<rant>I hate it (and all other sigils) too and would love concepts with definition checking, but</rant> but wasn’t sure I could get rid of it. I seem to recall a discussion where Richard and I concluded it was necessary but don’t recall the details. I guess the question is whether we need to know if something is an unexpanded pack is required for parsing. If I can’t reconstruct or rediscover an example, I will drop any objection to that.]
* Pack literals versus Type-Constructor
I see the proposed <> as a type-constructor operator. Not only for
literals. Currently we have only the builtin *, &, [], () and class
templates. With your proposal we will have also <>.
I was wondering if the following will be correct and what will be the
difference between T1 and T2 if any
template <class ...Ts>
using T1 = <Ts...>;
template <class ...Ts>
using T2 = Ts...;
IMO, only the first has a sens. I believe it is a good idea to see
<Ts...> as a type that has anonymous parameter pack type member data,
but it is not a parameter pack type.
[Oops. I did it both ways in the paper. You are correct that the first was intented.]
* Pack values - What is the type of decltype ({a,b})?
I like also the proposal to associate a type to a braced-init-list,
having expressions that don't have a type is not good.
Clearly a pack literal is the good candidate.
Been able to unpack a parameter pack type is a must and will simplify a
lot of library interfaces.
distanceFromMe(calculateTargetCoordinates()...)
However, the result type of calculateTargetCoordinates in
<double, double> calculateTargetCoordinates();
should be a type. Is a parameter pack type a type?
If Ts... is a type then we should be able to do[Yes. That is stated explicitly in the paper]
template <class ...Ts>
using T2 = Ts...;
In addition using the same operator that parameter packs would disable
to write the same code for a function returning a user defined type.
easy_tuple<double, double> calculateTargetCoordinates();
distanceFromMe(calculateTargetCoordinates()...); // compilation fails :(
This is why I believe that we would need another operator@ to transform
a Pack literal or user defined type to a parameter pack type that
doesn't conflict with the fold operator...
distanceFromMe( @ calculateTargetCoordinates() ...))
[I may be a little dense here, but not sure what the issue is. Can you give a more detailed explanation/example?]
* Named packs
Some months ago we were discussing in c++-standard ml about the
possibility of using anonymous structs as return type of a multiple
return function,
but they have already a well defined meaning that doesn't allows us to
reuse them in different context to mean the same type.
struct {string topSong; person president; double avgTemp}
someFactsAboutYear(int year);
Having named packs goes exactly in this direction, avoiding the backward
compatibility issue.
<string topSong, person president, double avgTemp>
someFactsAboutYear(int year)
Right.[I think you are agreeing with the approach in the paper, right?]
I will go even towards
<topSong(string), president(person), avgTemp(double) >
someFactsAboutYear(int year)
where topSong(string) is constructing a type with a specific accessor
Yes, I didn't wanted to post this sentence yet.[Would need to see a separate paper…]
Maybe not. I see <Ts...> as a product type and having direct access to the elements seem a basic operation on them.
* Access
[I am intrigued by these, but do any of them need to be part of this proposal?]
I believe that we need a direct access to the elements and its size as
we have fot tuple-like types and as I'm proposing for product-types in
general (P0327R0).
I woudl like to have some builtin operators to access parameter packs by
index.
Some have proposed alternative syntax to get the nth element (type) of a
parameter pack [N]T
The same operators could be used for pack literals types once we conver
to a parameter pack type
using R = <T,U>;
static_assert(sizeof...(@R)==2,"");
Some have proposed alternative syntax to get the nth element (type) of a
parameter pack [N]T
static_assert(is_same<[0]@R,T>{},"");
* Iteration
The iterator based interface to access heterogeneous containers should
be compared with the more functional interface Boost.Hana offers and
would need a separated proposal.
[I would be open to splitting off the iteration based interface into another proposal if the committee agrees]
* User-defined types
I don't understand what the following could mean
template <typename ...T> using easy_tuple<T...>... = <T...>;
What I don't understand is easy_tuple<T…>…[This is a “special notation” to allow a user-defined type T to say what T… is. An alternate notation might be
template <typename …T> using = T…;
I believe that we need to consider user defined types from the beginning as we need to consider generic functions on these kind of types.I explicitly say that the actual proposal would be in a separate paper and that this is for understanding vision/roadmap, so we have time to fine tune the notation.
I would like to be able to use the same unpack operator@ for pack
literals and for user defined product types.
<T,U> would have an implicit operator@ that give access to its elements
as a parameter pack type.
Don't having it would mean that algorithms can not manage both kind of
types.
Using a different operator@ would avoid the conflict with fold
expressions and so there will be no need for an user defined operator....
Instead of f(...t...); we should have
f(@t...);
Now the user needs just to define the *magic* operator@
template<typename ...T>
struct easy_tuple {
T... t;
T... & operator@() { return t; }
};
I say, *magic* because it doesn't return a type but a parameter pack type.
Note also that it return a reference to parameter pack type instead of a
parameter pack type of references.
It is similar, but the result is not the same and I believe it should be applied to <Ts...> also. Otherwise we will be unable to write generic algorithms for <Ts...> and for easy_tuple<Ts...>, which I believe is desirable.[Is operator@() vs the paper’s operator…() a bikeshed or is there a semantic distinction?
I don't know what easy_tuple<int, double>… could be. Do you mean what is the result type of easy_tuple<int, double>::operator...()?Also, how do you propose indicating that easy_tuple<int, double>… is the same as <int, double>…?
What’s in the paper, or something different?]
Another simple tuple could be
template<typename ...T>
struct easy_tuple : <Ts...> {};
Now the operator@ is inherited from <Ts...>.
What @ could be. I believe that for extension the operator is giving
access to any one of the members. We use operator*() to dereference a
pointer or reference like class.
I will suggest the use of this operator*
f(*tpl...);
No. There was a post in the std-proposal ML [1] about how to unpack tuples to value sequences[I’m still a little confused by your use of operator@. Do you have anything written up on it?]
template<typename ...Args)
func(Args&& ...pack)
{
auto rev_agg = ...; //Some
reverse-aggregate.
auto test1 = make_tuple(func(rev_agg)...); //Compile
error; nothing in the expression is a value sequence.
auto test2 = make_tuple(func([*]rev_agg)...); //Success.
Treats `rev_agg` as though it were a parameter pack.
auto test3 = make_tuple(func(rev_agg, pack)...); //Success.
`rev_agg` gets no special treatment. Every call to `func`
gets the same `rev_agg`, just as it would in current code.
auto test4 = make_tuple(func([*]rev_agg, pack)...); //Success.
Unpacks both `rev_agg` and `pack`. Only works if the two are
the same size, just like for two parameter packs.
}
[*]rev_agg was one of the proposed syntax for your UDT operator...
There were alsorev_agg
~ [2] was a library ideas to unpack tuples.
* Relation to Structured binding
If parameter pack types will be used to return multiple values from a
function, structured binding should work for them also.
< int, double> f();
auto [ a, b ] = f();
Wondering if structured binding shouldn't use <> instead of [] then.
auto < a, b > = f();
If <int, double> is a type, what could be the more natural pattern matching for <int, double>?[ <> doesn’t seem right because <ajl;ksdf> expressions are types, but maybe curly braces is most consistent with the paper?
auto {a, b} = f();]
Yes Michael, I will and you are completely right, it will be much easier. These exchanges have however help me to understand the details of the proposal and to identify where I believe than an alternative approach could be considered in Oulu.Hi Vicente,
A parameter pack is a type, but a pack expansion is not. See specific comments below for more details.
Best,
Mike
PS. Will you be in Oulu? I think some of these points may be easier to resolve in person than in many comment iterations.
From: Ext [mailto:ext-b...@lists.isocpp.org] On Behalf Of Vicente J. Botet Escriba
Sent: Sunday, June 5, 2016 5:52 PM
To: Evolution Working Group mailing list <e...@lists.isocpp.org>; C++ Library Evolution Working Group <lib...@lists.isocpp.org>; refle...@isocpp.org
Subject: Re: [Ext] About P0341R0: parameter packs outside of templates
Le 05/06/2016 à 21:48, Michael Spertus a écrit :
Thanks for the detailed feedback, Vicente. [Comments] below
-----Original Message-----
From: Ext [mailto:ext-b...@lists.isocpp.org] On Behalf Of Vicente J. Botet Escriba
Sent: Saturday, June 4, 2016 8:35 AM
To: Evolution Working Group mailing list <e...@lists.isocpp.org>; C++ Library Evolution Working Group <lib...@lists.isocpp.org>; refle...@isocpp.org
Subject: [Ext] About P0341R0: parameter packs outside of templates
Hi,
For me easy_tuple<double, double> and <double, double> should provide the same operator. I believe that easy_tuple<double, double> can not provide directly the expansion operator... and so <double, double> should provide it neither. We need for both an operator@ that allows the parameter pack expansion.
Again, note that user-defined types are not specifically being proposed except as a possible future. Having gotten that disclaimer out of the way, note that tuple<double, double> cannot act exactly like a parameter pack does without breaking compatibility. E.g.,the following example is legal C++14, and only the second argument of g is expanded by the ...
template<typename ...Ts> void f(Ts ...ts) { h(g(tuple<Ts...>(), ts)...); }
That is why the paper speculates that user-defined types will need to be prefaced by a sigil (either … as in the paper or @ as IIUC you are suggesting) before they can be expanded. However, for an actual pack, like those already in the language as well as those proposed in the paper, no sigil is required.
* User-defined types
I don't understand what the following could mean
template <typename ...T> using easy_tuple<T...>... = <T...>;
[This is a “special notation” to allow a user-defined type T to say what T… is. An alternate notation might be
template <typename …T> using = T…;
What I don't understand is easy_tuple<T…>…
I explicitly say that the actual proposal would be in a separate paper and that this is for understanding vision/roadmap, so we have time to fine tune the notation.
I believe that we need to consider user defined types from the beginning as we need to consider generic functions on these kind of types.
I will not be against separating the UDT part if <Ts...> has an operator@ that enable the parameter pack expansion.I’m inclined to think they can (and should) be separated. I think that simply making packs work and be constructible outside of templates is an unadulterated good even if user-defined classes are not supported (much like how current packs that are limited to template parameters have proven to be a great feature of C++11). I’m not sure that I see how the paper can limit potential opportunities around generic functions because existing C++11 parameter packs, which don’t require a sigil to expand, would need to be accommodated in the same way.
Nevertheless, I did put some thoughts in the paper about future extensions to user-defined types just in case there were interactions that we should be considering now…
I would like to be able to use the same unpack operator@ for pack
literals and for user defined product types.
<T,U> would have an implicit operator@ that give access to its elements
as a parameter pack type.
Don't having it would mean that algorithms can not manage both kind of
types.
Using a different operator@ would avoid the conflict with fold
expressions and so there will be no need for an user defined operator....
Instead of f(...t...); we should have
f(@t...);
Now the user needs just to define the *magic* operator@
template<typename ...T>
struct easy_tuple {
T... t;
T... & operator@() { return t; }
};
I say, *magic* because it doesn't return a type but a parameter pack type.
Note also that it return a reference to parameter pack type instead of a
parameter pack type of references.
[Is operator@() vs the paper’s operator…() a bikeshed or is there a semantic distinction?
It is similar, but the result is not the same and I believe it should be applied to <Ts...> also. Otherwise we will be unable to write generic algorithms for <Ts...> and for easy_tuple<Ts...>, which I believe is desirable.
I have used operator@ here to make evident that it is not an expansion operator... but the operator that give the possibility to do pack expansions.
When I use operator@ is to mean that we need to find out a good name. I'm not proposing to a new operator@ and even less to add a new encoding character.The … prefix is a notation of Richard’s to indicate that something can be expanded, so I think that is the same as your operator@. If it turns out to be necessary, perhaps yours is a better notation than the …. that multiple people have found ugly.
In your paper ... plays 3 roles. As parameter pack type expansion, as something used to disambiguate a parameter pact type member access in a dependent type and as a user defined operator to convert it to <Ts&...>.
I'm not completely against the name operator...(), but I would prefer something else. What I'm trying to explain is that the same operator is also needed for <Ts...>.But as a prefix, it means what your operator@ does, right? Bikeshedding as above, I’m not opposed to using @ rather than … as a prefix.
Also, how do you propose indicating that easy_tuple<int, double>… is the same as <int, double>…?
I don't know what easy_tuple<int, double>… could be. Do you mean what is the result type of easy_tuple<int, double>::operator...()?
Could you clarify this part of the paper?
Ok. We can forget it for the time being.That is a “special notation” inspired by my reading of Richards operator…() Clang branch (but don’t blame him for any of my misinterpretations J). I have not proposed a type for it. I have played around with this question a bit, and fear that what I would like and what I can get are not the same (one of many reasons why I am not formally proposing pack expansions of user-defined types in this paper…). Fortunately, since operator…() is not actually proposed in this paper, I am happy to remain agnostic as to whether it has a return type or is just a “special notation.”