Topic: Several problems regarding the R-Value Reference Proposal.
Author: pongba@gmail.com
Date: Tue, 30 Jan 2007 00:42:58 CST Raw View
Problem One :
Consider:
class A
{
public:
void f(){ i++; }
int i;
};
void g( A&& ra)
{
ra.f();
}
A a;
int main()
{
g(a); // is a.i effected ?
return 0;
}
According to N2118, ra is directly bound to a, so 'f' is invoked on a,
which would increment a.i.
But wouldn't this be counter-intuitive? I mean, when I'm writing g(A&&
ra), I'm expecting ra bound to a r-value, and modifying a r-value per
se shouldn't have any effect on the outside world, should it?
What I'm thinking is to modify the reference binding rule a little
bit, that is, when binding a l-value to a r-value reference, a l-value
to r-value conversion is made first, then the r-value reference is
bound to the resulting r-value.
And since we're on this subject, wouldn't it be weird if we can call
all the "normal" member functions through a r-value reference? "N1821-
Extending Move Semantics To *this" appears to hit the nail on the head
in this regard.
Problem Two:
About a few month ago I started a thread on comp.lang.std.c++( see
http://groups.google.com/group/comp.std.c++/browse_frm/thread/
93ea16fe97124900/6c39891c80b807c4#6c39891c80b807c4 ).
However, yesterday when I was reviewing that thread for some
information, I found some problems that I want to raise here again:
Below is the relevant quote:
> > "Joe Gottman" wrote:
> > > How about std::remove_reference?
> > > template <typename T> struct remove_reference
> > > {
> > > typedef T type;
> > > };
>
> > > template <typename T>
> > > struct remove_reference<T &>
> > > {
> > > typedef T type;
> > > };
>
> > > template <typename T>
> > > struct remove_reference<T &&>
> > > {
> > > typedef T type;
> > > };
>
> > Great example! Since the partial ordering of class template partial
> > specializations is defined in terms of that of function templates,
> > there seems to be a problem.
>
>
> Yes, I agree, excellent example. It sent me scurrying back to the CWG
> for expert advise on this one. James Widman was kind enough to
> explain
> things to me, and I'll try not to muddle his explanation too much.
> remove_reference works as Joe shows because in transforming the
> partial
> specialization into a function signature for the template type
> deduction
> process we use:
>
> template <typename T> void f(remove_reference<T&>);
> template <typename T> void f(remove_reference<T&&>);
>
> with an argument call like:
>
> f(remove_reference<int&>());
>
> I.e. there is no opportunity to apply 14.3.1p4 or 14.8.2.1p3.
>
> (and fwiw, this behavior is consistent with current compiler
> prototypes)
>
> -Howard
My question is that, according to the template argument deduction
rule( i.e. finding the template arguments that make P identical to A),
comparing remove_reference<T&&> against remove_reference<int&> *should
succeed*, because we can find "T = int& " that makes
remove_reference<T&&>( remove_reference<int & &&>(after substitution) -
> remove_reference<int&> ) identical to remove_reference<int&>.
Peter Dimov told me that type deduction doesn't work this way, he said
that P and A should be of the same form for type deduction to succeed.
While the definition of "same" here is subtle, and while I felt that
he's right in my gut, I can't yet find any clue in the standard that
supports this point of view. The only thing I can find is:
[14.8.2.1/3]
In general, the deduction process attempts to find template argument
values that will make the deduced A identical to A...
[14.8.2.4/1 ]
... but in each case a type that is specified in terms of template
parameters (call it P) is compared with an actual type (call it A),
and an attempt is made to find template argument values (...) that
will make P, after substitution of the deduced values (call it the
deduced A), compatible with A.
Is my interpretation right?
If not, then should the standard be clear about this? Before the r-
value reference is introduced, either interpretation would be okay
mostly, but not after, I think.
If so, then partial ordering rule is needed, although a correct
interpretation of the current partial ordering rule w.r.t. r-value
reference would suffice.
P.S. Howard was kindly enough to tell me that there's a core language
issue about it. It was raised by Peter Dimov, and he suggested to
restrict the "substituting A with A&" rule exactly to the case where P
is of the form "T&&" where T is a template parameter. While this can
cleanly solve the problem, I'm still wondering if the standard should
be clear about the way template argument deduction works, in
particular, I'm thinking that :
template<typename T>
class C; #1
template<typename T>
class C<T&&>; #2
C<int&> // choose #1 or #2 ?
Whether #1 or #2 is chosen depends on whether comparing T&& against
int& would succeed, and I think according to the current wording, it
should, with T deduced as int&( which would make T&& identical to
int&); but that'd be counter-intuitive, so I think the wording should
be more precise about the way template type deduction works.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: "=?iso-8859-1?q?Pedro_Lamar=E3o?=" <pedro.lamarao@gmail.com>
Date: Tue, 30 Jan 2007 12:48:54 CST Raw View
On 30 jan, 04:42, pon...@gmail.com wrote:
> Problem One :
> Consider:
> class A
> {
> public:
> void f(){ i++; }
> int i;
>
> };
>
> void g( A&& ra)
> {
> ra.f();
>
> }
>
>A a;
>
> int main()
> {
> g(a); // is a.i effected ?
> return 0;
>
> }
>
> According to N2118, ra is directly bound to a, so 'f' is invoked on a,
> which would increment a.i.
> But wouldn't this be counter-intuitive? I mean, when I'm writing g(A&&
> ra), I'm expecting ra bound to a r-value, and modifying a r-value per
> se shouldn't have any effect on the outside world, should it?
> What I'm thinking is to modify the reference binding rule a little
> bit, that is, when binding a l-value to a r-value reference, a l-value
> to r-value conversion is made first, then the r-value reference is
> bound to the resulting r-value.
The fact you are declaring a global A is confusing this example.
What's the meaning of calling g on a and not modifying it?
Doing that requires you to call g on a copy of a.
You seem to want rvalue references to be a mechanism that guarantees
the original object the reference binds to won't be ever affected --
so the compiler will force a copy to produce this guarantee. Am I
correct?
--
Pedro Lamar o
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: howard.hinnant@gmail.com (Howard Hinnant)
Date: Fri, 2 Feb 2007 18:20:15 GMT Raw View
In article <1170139251.993287.285170@p10g2000cwp.googlegroups.com>,
pongba@gmail.com wrote:
> Problem One :
> Consider:
> class A
> {
> public:
> void f(){ i++; }
> int i;
> };
>
> void g( A&& ra)
> {
> ra.f();
> }
>
> A a;
>
> int main()
> {
> g(a); // is a.i effected ?
> return 0;
> }
>
> According to N2118, ra is directly bound to a, so 'f' is invoked on a,
> which would increment a.i.
> But wouldn't this be counter-intuitive? I mean, when I'm writing g(A&&
> ra), I'm expecting ra bound to a r-value, and modifying a r-value per
> se shouldn't have any effect on the outside world, should it?
> What I'm thinking is to modify the reference binding rule a little
> bit, that is, when binding a l-value to a r-value reference, a l-value
> to r-value conversion is made first, then the r-value reference is
> bound to the resulting r-value.
Consider someone writing their own smart pointer type. They would like
a member function called grab, which takes a unique_ptr, and transfers
the resource to this:
template <class T>
class my_smart_ptr
{
T* ptr_;
public:
...
void grab(std::unique_ptr<T>&& p) {ptr_ = p.release();}
...
};
What they are saying here is that they want to be able to grab the
resource from a unique_ptr, whether it is an lvalue or rvalue:
std::unique_ptr<int> source();
int main()
{
my_smart_ptr<int> s;
std::unique_ptr<int> u(new int);
s.grab(u); // ok
s.grab(source()); // also ok
}
If grab took unique_ptr by value, it would only accept rvalues.
If grab took unique_ptr&, it would only accept lvalues.
If grab took const unique_ptr&, it would not be able to call release()
on it, at least not without a const_cast.
unique_ptr&& is the only parameter which does what the author desires in
this case. Imho this is a reasonable use-case to support.
> And since we're on this subject, wouldn't it be weird if we can call
> all the "normal" member functions through a r-value reference? "N1821-
> Extending Move Semantics To *this" appears to hit the nail on the head
> in this regard.
I am in favor of N1821. However I'm not sure I follow you here. Today
one can call any member function with an rvalue this. For example:
std::string s1, s2;
std::string s3 = (s1+s2).append("suffix");
N1821 seeks to allow overloading of member functions on whether this is
an lvalue or rvalue.
-Howard
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: pongba@gmail.com
Date: Sat, 3 Feb 2007 00:32:33 CST Raw View
On Feb 3, 2:20 am, howard.hinn...@gmail.com (Howard Hinnant) wrote:
> ... unique_ptr&& is the only parameter which does what the author desires in
> this case. Imho this is a reasonable use-case to support.
Yeah, it would be.
But shouldn't we just use overloading for this seemingly isolated use-
case? I mean, it'll be a little duplicating, but we could forward to
the l-value overload version in the r-value one, e.g.
. grab(unique_ptr<T> & up)
{
... // do the job
}
. grab(unique_ptr<T>&& up)
{
grab(up); // isn't this neat?( 'up' is treated here as a l-value,
right? )
}
And since you've brought this case, it actually inspired me to another
case, it's kinda more important, I think.
The current perfect forwarding mechanism is supported by deducing T&&
differently in the case of a r-value and a l-value. And since Peter
Dimov suggested in Core Lang Issue 606 that this special rule should
be restricted to "T&&", where T is a template parameter, exclusively,
at the first glance it may make much sense, but the use-case you've
given here made me think that maybe sometimes it's not that
unreasonable to forward on a "restricted" basis, e.g.
template<typename T>
void forward(MyC<T>&& p)
{
do(p);
}
The purpose here is to forward only those objects of type MyC<T>, but
since the special deduction rule doesn't apply here, this would
silently fail!
Of course, I know that the type-check could be deferred to the point
where the callee is instantiated, while leaving the interface of the
wrapper(i.e. forwarder) generic(i.e. T&&). But, if this isn't a
general-purpose forwarder(such like std::bind1st), maybe I'd want to
restrict the interface, no matter whether to show my intention or just
for earlier type-check.
That said, I don't think I have any idea this could be supported :(
"MyC<T>&&" obviously *should* be a r-value reference, and if it
weren't, it'd be counter-intuitive.
> > And since we're on this subject, wouldn't it be weird if we can call
> > all the "normal" member functions through a r-value reference? "N1821-
> > Extending Move Semantics To *this" appears to hit the nail on the head
> > in this regard.
>
> I am in favor of N1821. However I'm not sure I follow you here. Today
Yeah, my fault:=)
Actually I was thinking that by restricting normal member functions to
be only callable on l-values, and supporting the so-called r-value
member functions, the problem would disappear and the type-system more
crystal-clear.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]