On 2014-02-27 19:33,
leszek....@gmail.com wrote:
> On Thursday, 27 February 2014 18:52:20 UTC, Matthew Woehlke wrote:
>> should we also allow e.g.:
>>
>> (int a, double b) = foo();
>
> I was thinking this too, but I'm a little bit worried about having
> parenthesised expressions as L-values -- I'm not sure how pleased the
> parser people would be about something like this, especially since (a,b) is
> a perfectly valid L-value (and not a tuple unpacking). I'm not sure how
> common it would be for someone to want to unpack a tuple into different
> types than are found in the tuple, so perhaps this is an example where it's
> best to optimise for the common case.
But it's not just the different-types case. It's also type modifiers
e.g. 'const', '&', '&&'.
(I wasn't even thinking *different* types anyway, but specifying the
types explicitly rather than using 'auto'.)
Right now, e.g. '(int a, double b)' is not valid syntax; it seems it
should be possible to detect that the components look like declarations
and treat them as tuple unpacking. But I'm not a parser writer, so it
wouldn't hurt to have someone who is weigh in.
Going further, should:
int a;
double b;
(a, b) = foo(); // foo() -> tuple<int, double>
...be allowed? I'd say 'no' since the above is legal in current C++ if
foo() -> double (or something convertible to double). IOW, only invoke
tuple initialization if some An (referring to syntax below) is non-empty.
>> Also, I would like if the following are also valid:
>>
>> auto const&& (a, b) = foo(); // a and b are both const
>> auto (const&& a, b) = foo(); // a -> auto const&&, b -> auto
>
> I see no (immediate) reason why not, though I'm not sure how well this
> would interact with, for example, tuples containing references.
They should behave exactly as I illustrated later in my previously mail,
i.e. the second is equivalent to:
auto&& __temp = foo();
auto const&& a = get<0>(__temp);
auto b = get<1>(__temp);
So there is no new behavior being introduced here.
> Would auto(a,b) cause unnecessary copies?
This (IMHO) should be exactly equivalent to 'auto a = get<0>(...)',
etc.. If that would cause copies, then so will 'auto (a, ...)'.
> Would decltype(auto) (a,b) need to be a thing?
I'm not sure it is possible; it would imply knowing what tuple or
tuple-like type 'auto (a,b)' was assigned from (e.g. tuple, pair, ...?).
(More interesting: do we allow '(int a, double b)' as a bare
declaration? We *could*, though I don't see a benefit in doing so.)
>> Related: bonus points if 'auto (a,b)' can also be used with std::pair.
>> Maybe it should be implemented like range-based for, i.e. creates an
>> anonymous temporary and uses a well-known function ('get<index>') to get
>> each value. Then as long as there is a std::get<0>(std::pair<...>) this
>> will just magically work, and can also be extended to user types.
>
> Also exactly what I was thinking, calling get<i> using ADL in a similar way
> to range-based for's ADL use of begin. We'd probably also need to check if
> the number of arguments matches the number of variables, which would be
> done using an ADL of tuple_size.
Do we? We could also allow the caller to simply discard unneeded
elements. This would tremendously simplify things (no need to check
tuple_size or to implement it for user types; just rely on get<i> to be
a compile error if no such element i) as far as the implementation.
>> Also, the above would mean the compiler effectively is just generating
>> code like in your (elided) examples, [...]
>>
>> [A0] ([A1] N1, [A2] N2, ...) = expr;
>>
>> ...is expanded by the compiler to become:
>>
>> auto&& __temporary__ = expr;
>> A0 A1 N1 = get<0>(__temporary__);
>> A0 A2 N2 = get<1>(__temporary__);
>
> With the small difference that it all counts as a single statement (single
> expression?)
I think yes, if it matters. (I wasn't thinking of this as an actual code
transformation that would then be subject to rules where it would
matter, but rather the compiler would generate assembly "as if" the code
was as above. IOW, scoping, building of symbol trees, etc. has already
been performed. Actually this works even for range-based for, as the
assignment of the value happens inside the loop. Implying of course that
the range-based for transformations happen first. So, also, similar to
the "as-if code expansion" done to implement range-based for.)
Interesting question: is this a permissible declaration inside of if()?
And if so, what assignment is used as the conditional expression?
(First? Last? All of them?)
--
Matthew