auto ref with templated functions needs to retain its current
behavior. Changing it would not only break existing code, but
it would lose what we have in terms of perfect forwarding
(IIRC, it's not quite perfect forwarding, but it's close, and
we'd be much farther from it without auto ref).
Ok, I thought so too
If we want to have non-templated functions which can accept
both rvalues and lvalues without copying the lvalues, then we
need have a way to mark those parameters so that they're ref
and then have an invisible, temporary variable inserted to hold
a copy of an rvalue so that it can be passed by ref and
accepted by the function as well instead of just accepting
lvalues.
That is what auto ref for non-templates would do (and what I
planned to do): if the passed argument is not an lvalue, a
temporary is constructed which is passed by ref.
If we want that to work with both non-templated and templated
functions, then we need a new syntax. If we're willing to have
them work with just non-templated functions, then we could
reuse auto ref for that (and _maybe_ we could have the compiler
optimize auto ref on templates to mean the same thing when it
can determine that it's safe to do so and thus avoid extra
template instantiations, but I question that that will happen).
But then we only get it for non-templated functions, and auto
ref means somethings slightly different for templated and
non-templated functions, which sucks, but I'm not sure that
it's ultimately all that big a deal.
AFAIK Andrei wanted 'auto ref' as the syntax which accepts both,
lvalues and rvalues. That's why I'm asking if the current
behaviour for auto ref for templates should change, or not. If
not, we have (as you said) two meanings of auto ref, what is not
optimal, but not so bad either (IMO).
But if I had the choice, I would change it for both, so that both
create a temporary variable for rvalues.
I _definitely_ think that it would be a huge mistake for ref in
general to accept rvalues. If we did that, then suddenly, ref
would be used everywhere, and you couldn't tell when someone
wanted to actually set the ref argument to something or whether
they were just trying to avoid extraneous copies of lvalues.
I agree with that 100%.
I'd much rather have no way to have a parameter accept both
rvalues and lvalues without copying the lvalues with
non-templated functions than have ref accept rvalues.
So, basically, I think that we have three options:
1. Do nothing. If you want a function parameter to accept both
lvalues and rvalues efficently, then either duplicate it with
various overloads to achieve that or templatize it and use auto
ref so that the compiler will do that for you.
But that means we get (at worst) 2^N functions. And note that
each function contains the whole body, not just a call to one of
the previous creations.
That is really huge.
If it would be only a call to one of the previous creations like:
----
struct S { }
void test()(auto ref S s) {
}
test(S());
S s = S();
test(s);
----
is expaned to
----
void test(ref S s) {
}
void test(S s) {
test(s); // Note that
}
----
it would be fine. But not optimal either, since these functions
can contain bugs which are never explored if your coverage is not
100%, because template methods are only instantiated if they are
called. (Hope you know what I mean, my english is not that
pretty....)
2. Extend auto ref so that it works with non-templated
functions by inserting a temporary variable for rvalues so that
they can be passed to the function by ref. Templated functions
stay as they are.
This is what I wanted to do.
3. Add a new attribute - e.g. @rvalue ref - which inserts a
temporary variable for rvalues so that they can be passed by
ref, and it works with both templated and non-templated
functions.
Right now, we seem to be doing #1, and we have never officially
decided whether that's permanent. Andrei in particular has
resisted adding a new attribute, and to some extent, I agree
that that's undesirable, but it _would_ allow us to solve this
problem for both templated and non-templated functions, which
we can't really do otherwise. So, I don't know how reasonable
or feasible #3 is at this point. #2 probably wouldn't be that
hard to get in, but then it only works with non-templated
functions, and it complicates the meaning of auto ref in an
already complicated language.
Honestly, at this point, I don't know how much this issue
really matters. It's annoying that we don't have rvalue
references, but in general, we're living without them just
fine, and we're heading toward templatizing almost everything
for ranges anyway, in which case, the current version of auto
ref will work just fine with most code (though that extraneous
template bloat _is_ ugly). So, while I'd like to have rvalue
references, I also think that we can get by just fine without
them.
If we _were_ going to add rvalue references, at this point, I'd
probably lean towards a new attribute, because it's cleaner and
more flexible that way, but it _does_ mean adding a new
attribute, and I don't know if that's worth it.
- Jonathan M Davis