On 2016-12-19 15:34, T. C. wrote:
> 1. The first line of "Parameter Pack Slicing" doesn't seem to be formatted
> correctly: note all the backticks.
It's correct, as can be seen in the HTML. Double ``s are markup for
literal text; the unbalanced `s appear literally in the output. Here's
the output (sans rich text):
... operator, `[` <slicing_expression> `]`, which ...
... one of <index> or [<index>] `:` [<index>], where ...
The intent is that ``-marked text denotes a literal token. (This is
somewhat important when []s are being thrown around both as literal
tokens and this-is-optional indicators... Unfortunately, it is not easy
in reST to have text that is both bold and literal.)
> 2. I don't buy the argument in "improving std::apply" about tuple_cat. You
> can just make a helper to create a tuple of references from a plain tuple
> and use tuple_cat on the result of that.
...but you still have to build that new tuple, and it sounds like your
invocation is still going to be non-trivially more complicated that the
postulated std::apply taking multiple tuples. (Anyway, this is not part
of the proposal, just an example of "stuff you can do with this feature".)
> Also, the code fragment in that section makes plenty of copies,
> ironically, and its broken syntax is also distracting.
Which syntax is broken?
--
Matthew
Hi,
glad to see such a proposal.
I'm not against redefining sizeof for product types, but it will
be worth mentioning the syntax is possible sizeof([:]t...) without
the redefinition.
The <double, double> returned in
<double, double> calculateTargetCoordinates();
is not a parameter pack but a pack type as defined in P0341. This
is of course something new.
I like the [start:stop] operator on parameter packs and product
types. I prefer [:] to the user defined operator... proposed in
P0341.
Pack types as defined in P0341 should accept this slice operator
(we shoild consider Pack types as product types). I'm not sure we
will need that Pack types provide directly the expansion
operator....
Have you considered strides [start:stop:step]? reverted slices [start:stop:-1]?
(see https://docs.python.org/2.3/whatsnew/section-slices.html)
The main difference between the
proposed slice operator and python slices is that the result is
not a type, but a parameter pack, that can not be on the LHS of
an assignment. Have you considered this possibility?
Vicente
The main difference between the proposed slice operator and python slices is that the result is not a type, but a parameter pack, that can not be on the LHS of an assignment. Have you considered this possibility?
template<typename... Ts>
void f(Ts&&... ts)
{
(... , ([1:3]ts = 42)); // pack on LHS of assignment, plus a C++17 fold-expression with operator-comma
}
int main()
{
static int v0,v1,v2,v3,v4;
f(v0,v1,v2,v3,v4);
assert(v0==0 && v1==42 && v2==42 && v3==0 && v4==0);
}
>>> x = [0,1,2,3,4]
>>> x[1:3] = [42]
>>> print x
[0, 42, 3, 4]
>>> print 'The above is actually syntactic sugar for:'
The above is actually syntactic sugar for:
>>> x.__setitem__(slice(1,3), [42])
>>> print x
[0, 42, 4]
That is, in Python, an assignment whose LHS is a slice-expression actually changes the length of the complete list being sliced! I found some details on Python's implementation of slices-on-the-LHS here. AFAIK, it's purely a syntactic-sugar construct — there is no way to "capture" a slice-expression and later use it to mess with the original complete list, any more than there's a way to "capture" or "perfect-forward" a heterogeneous braced-initializer-list in C++. Notice that slice is a built-in type (read: standard library type) in Python, but it's just a tag type for holding a couple of ints; the actual magic here is happening in x's __setitem__ method (read: a special member function).
Notice also that Python does not support slice-on-the-LHS for all sliceable types. Python's tuples, which are heterogeneous and immutable, do not support slice-on-LHS or even index-on-LHS.
>>> x = (0,1,2,3,4)
>>> x[1:3]
(1, 2)
>>> x[0] = 42
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> x[1:3] = (42,)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
Notice that slicing a tuple gives me a tuple, whereas slicing a list gave me a list. This is determined entirely by the behavior of x.__getitem__(slice(1,3)) (read: another special member function). Python has a crazy rich set of special member functions: basically any member function whose name begins and ends with double-underscore is available to assign special meaning to, and they've been taking advantage of that.
HTH,
Arthur
IIUC (having only skimmed Matthew's paper but debated re packs in this forum often enough ;)) the syntax
template<typename... Ts>
void f(Ts&&... ts)
{
(... , ([1:3]ts = 42)); // pack on LHS of assignment, plus a C++17 fold-expression with operator-comma
}
int main()
{
static int v0,v1,v2,v3,v4;
f(v0,v1,v2,v3,v4);
assert(v0==0 && v1==42 && v2==42 && v3==0 && v4==0);
}would indeed fall out naturally. But I believe that what Vicente was referring to is Python's syntax for assigning into a slice of a list:
[1:3]ts#0 = 42;
[1:3]ts#1 = 42;
...
[1:3]ts#N-1 = 42;
ts#1 = 42;
ts#2 = 42;
auto manhattan_distance d = std::abs([:]v) + ...; auto dot = [:]v * ...;
Also, the paper has these two examples:auto manhattan_distance d = std::abs([:]v) + ...; auto dot = [:]v * ...;Aside from the extra "d", what are these supposed to do? Both Manhattan distance and dot product are functions of two vectors, so I don't entirely understand this example.
auto manhattan_distance = std::abs([:]v1 - [:]v2) + ...
auto dot = ([:]v1 * [:]v2) + ...;
The main difference between the proposed slice operator and python slices is that the result is not a type, but a parameter pack, that can not be on the LHS of an assignment. Have you considered this possibility?
That can easily be handled by unpacking it into a tuple of references, which can be assigned to.
I really like this feature for packs. For "product types" such as tuples I'm more reserved.
It seems that converting the product type object to a value pack is the principal operation, and that any slicing should take place after the product type object has been converted to a pack. Using the "nop slice" for this purpose feels contrived.
> Given what slicing means in Python and what how unpacking typically works
> in C++, I think the more natural falling out is:
>
> [1:3]ts#0 = 42;
> [1:3]ts#1 = 42;
> ...
> [1:3]ts#N-1 = 42;
I'm... not quite sure what you're saying here?
(... , ([1:3]ts = 42));
template <class F, class... Ts>
void invoke(F f, Ts... ts) { ... }
I'm posting an update, since there have been non-trivial changes to the
examples and some discussion questions, partly thanks to some in depth
discussions with Bengt Gustafsson.
Again, feedback appreciated, especially on the examples and discussion
points. (The original summary, for context, is quoted below.)
Matthew
On Thursday, December 28, 2017 at 2:37:21 PM UTC+2, mihailn...@gmail.com wrote:Hello, the syntax has some major problemsstd::tuple<int, int, int> t;[0][1]t;
Should I read left to right or right to left?I know the answer - right to left. However - we are back in the reverse invocation of get<0>(get<1>())!Even worse:[0]t[1];
Is it a tuple element, which is an array or an array element which is a tuple?!?Sure, there is an answer, based on operator precedence, but one must know and evaluate the precedence in his head to be able to read the code.Ironically even get<> is better in that case!
adv is a tuple(-like) created not from a single slice or an index, but a mix indices and slices!The I can be either an size_ or a pair<size_t, size_t> or a pair<optional<size_t>, optional<size_t>> IFF the index is the last or first in the pack.This way we have complete freedom over what we select - we can cherry-pick some elements and consume multiple, separate groups of others.
//with your version
std::forward<Args.[I]>(args.[I]);
//with the prefix version
[I]std::forward<Args>(args)
template<class... Args>
void print_reverse(Args&&...args)
{
if constexpr (sizeof...(Args) > 0)
{
auto indexs = std::make_index_sequence<sizeof...(Args) - 1>{};
std::cout << [-1]indexs;
((std::cout << [sizeof...(Args) - [:]indexs - 1]std::forward<Args>(args)), ...);
}
std::cout << std::endl;
}
template<class... Args>
void print_reverse(Args&&...args)
{
if constexpr (sizeof...(Args) > 0)
{
auto indexs = std::make_index_sequence<sizeof...(Args) - 1>{};
std::cout << indexs.[-1];
((std::cout << std::forward<Args.[sizeof...(Args) - indexs.[:] - 1]>(args.[sizeof...(Args) - indexs.[:] - 1])), ...);
}
}