Topic: N2857: Iterator concepts are flawed
Author: Greg Herlihy <greghe@mac.com>
Date: Mon, 8 Jun 2009 09:36:29 CST Raw View
On Jun 7, 7:16 pm, Daniel Kr gler <daniel.krueg...@googlemail.com>
wrote:
> On 7 Jun., 00:43, Greg Herlihy <gre...@mac.com> wrote:
>
> The observation and conclusion of the OP are completely right:
> Concept MoveConstructible is currently broken after N2831 had
> been applied. The reason - which SG has correctly pointed out - is
> the Constructible<T, RvalueOf<T>::type> requirement in
> MoveConstructible.
Actually, SG did not point any problem with any Constructible
requirement (probably because there are none to be found).
> Note, that RvalueOf<T>::type always returns
> an rvalue reference, independent of the argument type. So, if
> the T provided to the concept *is* in fact an lvalue reference,
> this ensures that RvalueOf<T>::type returns effectively T'&&
> were T' is equivalent to the result of remove_reference<T>::type.
> Now we have effectively a Constructible<T, T'&&> to satisfy,
And an lvalue reference easily satisfies this Constructible<T, T'&&>
requirement.
After all, an lvalue reference may be initialized with either: another
lvalue reference or with an rvalue reference; the changes made by
N2831 did nothing to alter this fact. (Now, N2831 did eliminate the
implicit conversion in the -opposite- direction, that is, from an
lvalue- to an rvalue-reference, but did not change the conversion in
the direction we care about).
> ...which has a T::T(T'&&) requirement. This is essentially a
> requirement that says that an rvalue reference is implicitly
> convertible to T, which is an lvalue reference. Exactly this
> is what SG deduced.
No, SG did not "deduce" any problem here - no doubt because he did not
confuse the Constructible concept (in which one type initializes
another) with the much more stringent "Convertible" concept (in which
one type implicitly converts to another). Nor did SG mistake the
(legal) rvalue-reference-to-lvalue reference conversion for the (N2831-
banned) lvalue- to rvalue-reference conversion in the opposite
direction.
In reality, SG identified a problem in RvalueOf's Convertible<T&,
type> requirement. The problem is that - with the changes made by
N2831 - an lvalue reference no longer implicitly converts to an rvalue
reference; so, an lvalue reference would no longer meet RvalueOf's
Convertible requirement.
But what SG (among others) failed to notice, is that N2831 also
changed RvalueOf's Convertible<T&, type> requirement to an
ExplicitlyConvertible<T&, type> requirement - and adjusted
static_cast<> to allow an lvalue reference to be cast explicitly to an
rvalue reference.
So, in fact, (and to its authors' credit) N2831 anticipated how the
elimination of the lvalue-to-rvalue-reference implicit conversion
would affect the MoveConstructile concept. And the authors did in fact
make the necessary changes to ensure that an lvalue reference would
remain a MoveConstructible type.
To summarize: N2831 did not break the MoveConstructible concept, and
an lvalue reference is a MoveConstructible type.
Greg
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Mon, 8 Jun 2009 09:36:04 CST Raw View
On 8 Jun., 04:16, Daniel Kr gler <daniel.krueg...@googlemail.com>
wrote:
>
> The observation and conclusion of the OP are completely right:
> Concept MoveConstructible is currently broken after N2831 had
> been applied. The reason - which SG has correctly pointed out - is
> the Constructible<T, RvalueOf<T>::type> requirement in
> MoveConstructible. Note, that RvalueOf<T>::type always returns
> an rvalue reference, independent of the argument type. So, if
> the T provided to the concept *is* in fact an lvalue reference,
> this ensures that RvalueOf<T>::type returns effectively T'&&
> were T' is equivalent to the result of remove_reference<T>::type.
That's the idea, yes. But as previously pointed out, RvalueOf is
broken (see also the thread "N2857: issues with concept reqruiements
and references"). I'm not sure if MoveConstructible is to blame here.
Obviously Constructible<T, RvalueOf<T>::type> is necessary to
guarantee that a T can be initialized with the result of std::move for
a parameter that refers to an object of the same type.
So, instead of changing MoveConstructible I would suggest fixing
RvalueOf and adding an additional concept that is weaker than
MoveConstructible and applies to lvalue references as well:
auto concept Forwardable<typename T> : Constructible<T,T&&> {}
(IMHO, this should be used instead of MoveConstructible to constrain
some types in the standard library like for parameter types in binders/
wrappers memfun_t, std::function, ...)
> Unfortunately the assertions of SG and Sebastian are absolutely
> correct (The "unfortunately" denotes the state of affairs, not the
> persons).
> To SG: Your postings have been read, unfortunately I had no
> time yet to reply. Please be ensured that your observations
> are read and are taken seriously!
Thank you for your feedback!
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Mon, 8 Jun 2009 11:40:34 CST Raw View
On 8 Jun., 17:36, Greg Herlihy wrote:
> On Jun 7, 7:16 pm, Daniel Kr gler wrote:
>
> > Note, that RvalueOf<T>::type always returns
> > an rvalue reference, independent of the argument type. So, if
> > the T provided to the concept *is* in fact an lvalue reference,
> > this ensures that RvalueOf<T>::type returns effectively T'&&
> > were T' is equivalent to the result of remove_reference<T>::type.
> > Now we have effectively a Constructible<T, T'&&> to satisfy,
>
> And an lvalue reference easily satisfies this Constructible<T, T'&&>
> requirement.
...not in case T'&& is an rvalue reference.
> After all, an lvalue reference may be initialized with either: another
> lvalue reference or with an rvalue reference;
Sorry, you are completely off here. There is no and never was an
implicit conversion from unnamed rvalue references to lvalue
references. This only works the target is an lvalue-ref-to-const:
int&& foo();
int & bar = foo(); // ill-formed
int const& baz = foo(); // OK
[snip]
> But what SG (among others) failed to notice, is that N2831 also
> changed RvalueOf's Convertible<T&, type> requirement to an
> ExplicitlyConvertible<T&, type> requirement - and adjusted
No, I did not fail to notice that. Why do you think so? This
conversion requirement is not a problem. The problem is with the other
conversion requirement that remained implicit. (see elsethread)
> To summarize: N2831 did not break the MoveConstructible concept, and
> an lvalue reference is a MoveConstructible type.
Well, RvalueOf was already broken before N2831. And lvalue references
didn't satisfy MoveConstructible before N2831 either. So yes, N2831
didn't change that. :-)
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Mon, 8 Jun 2009 13:21:33 CST Raw View
On 8 Jun., 19:40, SG <s.gesem...@gmail.com> wrote:
> On 8 Jun., 17:36, Greg Herlihy wrote:
>
> > To summarize: N2831 did not break the MoveConstructible concept, and
> > an lvalue reference is a MoveConstructible type.
>
> Well, RvalueOf was already broken before N2831.
This is wrong. I apologize for any confusion. See elsethread for a
"dissection" of RvalueOf.
> And lvalue references
> didn't satisfy MoveConstructible before N2831 either.
This remains true, though.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Wed, 3 Jun 2009 16:52:53 CST Raw View
Hi!
I just noticed the Iterator concept (N2857.pdf)
concept Iterator<typename X> : Semiregular<X> {
MoveConstructible reference = typename X::reference;
...
}
and wanted to point out that the MoveConstructible requirement for the
reference type renders this concept pretty much useless. Lvalue
references are not MoveConstructible.
For other reference & concept related issues with N2857.pdf (for
example: RvalueOf is broken, std::function is over-constrained) see my
older posts in this group.
I'd really appreciate some feedback. If this is not the right forum
for these kinds of posts, please point me into the right direction.
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: wasti.redl@gmx.net
Date: Thu, 4 Jun 2009 21:30:30 CST Raw View
On Jun 4, 12:52 am, SG <s.gesem...@gmail.com> wrote:
> Hi!
>
> I just noticed the Iterator concept (N2857.pdf)
>
> concept Iterator<typename X> : Semiregular<X> {
> MoveConstructible reference = typename X::reference;
> ...
> }
>
> and wanted to point out that the MoveConstructible requirement for the
> reference type renders this concept pretty much useless. Lvalue
> references are not MoveConstructible.
It seems that N2857 is full of places where the assumption
CopyConstructible : MoveConstructible is made. But it also contains
the update that rvalue references cannot be initialized with lvalues,
so this assumption is wrong.
Every single occurrence of CopyConstructible and MoveConstructible
should probably be audited.
Sebastian
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Greg Herlihy <greghe@mac.com>
Date: Sat, 6 Jun 2009 16:43:20 CST Raw View
On Jun 4, 8:30 pm, wasti.r...@gmx.net wrote:
> On Jun 4, 12:52 am, SG <s.gesem...@gmail.com> wrote:
>
> > I just noticed the Iterator concept (N2857.pdf)
>
> > concept Iterator<typename X> : Semiregular<X> {
> > MoveConstructible reference = typename X::reference;
> > ...
> > }
>
> > and wanted to point out that the MoveConstructible requirement for the
> > reference type renders this concept pretty much useless. Lvalue
> > references are not MoveConstructible.
Lvalue references do meet the requirements of MoveConstructible.
Specifically: a type, T, is MoveConstructible if a T object can be
initialized with a T&& value. Now, due to reference "collapsing", the
initializer's type, T&& - when T is an lvalue reference - becomes
simply, T itself. And since an lvalue reference can in fact be
initilialized by another lvalue reference (of the same type), an
lvalue reference is a MoveConstructible type.
> It seems that N2857 is full of places where the assumption
> CopyConstructible : MoveConstructible is made. But it also contains
> the update that rvalue references cannot be initialized with lvalues,
> so this assumption is wrong.
There is no assumption needed here. CopyConstructible does "refine"
MoveConstructible. In other words, every CopyConstructible type is
also a MoveConstructible type (but, not necessarily, the other way
around.)
Greg
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Sun, 7 Jun 2009 20:16:06 CST Raw View
On 7 Jun., 00:43, Greg Herlihy <gre...@mac.com> wrote:
> On Jun 4, 8:30 pm, wasti.r...@gmx.net wrote:
>
> > On Jun 4, 12:52 am, SG <s.gesem...@gmail.com> wrote:
>
> > > I just noticed the Iterator concept (N2857.pdf)
>
> > > concept Iterator<typename X> : Semiregular<X> {
> > > MoveConstructible reference = typename X::reference;
> > > ...
> > > }
>
> > > and wanted to point out that the MoveConstructible requirement for the
> > > reference type renders this concept pretty much useless. Lvalue
> > > references are not MoveConstructible.
>
> Lvalue references do meet the requirements of MoveConstructible.
> Specifically: a type, T, is MoveConstructible if a T object can be
> initialized with a T&& value. Now, due to reference "collapsing", the
> initializer's type, T&& - when T is an lvalue reference - becomes
> simply, T itself. And since an lvalue reference can in fact be
> initilialized by another lvalue reference (of the same type), an
> lvalue reference is a MoveConstructible type.
The observation and conclusion of the OP are completely right:
Concept MoveConstructible is currently broken after N2831 had
been applied. The reason - which SG has correctly pointed out - is
the Constructible<T, RvalueOf<T>::type> requirement in
MoveConstructible. Note, that RvalueOf<T>::type always returns
an rvalue reference, independent of the argument type. So, if
the T provided to the concept *is* in fact an lvalue reference,
this ensures that RvalueOf<T>::type returns effectively T'&&
were T' is equivalent to the result of remove_reference<T>::type.
Now we have effectively a Constructible<T, T'&&> to satisfy,
which has a T::T(T'&&) requirement. This is essentially a
requirement that says that an rvalue reference is implicitly
convertible to T, which is an lvalue reference. Exactly this
is what SG deduced.
> > It seems that N2857 is full of places where the assumption
> > CopyConstructible : MoveConstructible is made. But it also contains
> > the update that rvalue references cannot be initialized with lvalues,
> > so this assumption is wrong.
>
> There is no assumption needed here. CopyConstructible does "refine"
> MoveConstructible. In other words, every CopyConstructible type is
> also a MoveConstructible type (but, not necessarily, the other way
> around.)
No, unfortunately the assertions of SG and Sebastian are absolutely
correct (The "unfortunately" denotes the state of affairs, not the
persons).
To SG: Your postings have been read, unfortunately I had no
time yet to reply. Please be ensured that your observations
are read and are taken seriously!
Greetings from Bremen,
- Daniel
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Sun, 7 Jun 2009 21:52:40 CST Raw View
On 7 Jun., 00:43, Greg Herlihy <gre...@mac.com> wrote:
> On Jun 4, 8:30 pm, wasti.r...@gmx.net wrote:
> > On Jun 4, 12:52 am, SG <s.gesem...@gmail.com> wrote:
>
> > > I just noticed the Iterator concept (N2857.pdf)
> > > concept Iterator<typename X> : Semiregular<X> {
> > > MoveConstructible reference = typename X::reference;
> > > ...
> > > }
> > > and wanted to point out that the MoveConstructible requirement for the
> > > reference type renders this concept pretty much useless. Lvalue
> > > references are not MoveConstructible.
>
> Lvalue references do meet the requirements of MoveConstructible.
> Specifically: a type, T, is MoveConstructible if a T object can be
> initialized with a T&& value. Now, due to reference "collapsing", the
> initializer's type, T&& - when T is an lvalue reference - becomes
> simply, T itself. And since an lvalue reference can in fact be
> initilialized by another lvalue reference (of the same type), an
> lvalue reference is a MoveConstructible type.
You are wrong.
MoveConstructible<T> contains two associated requirements:
RvalueOf<T> && Constructible<T,RvalueOf<T>::type>
where RvalueOf<T>::type is *always* supposed to be an rvalue
reference. The collapsing rule is specifically worked around in
RvalueOf (see concept_map for lvalue references). Still, RvalueOf
contains associated Convertible requirements that an lvalue reference
cannot meet which makes the concept_map RvalueOf<T&> ill-formed. So,
an lvalue reference doesn't satisfy RvalueOf. Since RvalueOf is an
associated requirement of MoveConstructible, this would be another
reason why lvalue references are not MoveConstructible. (Both of the
associated requirements I mentioned above are not met).
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]