Discussion:
Validity of copy-elision of return of conversion function, in direct-initialization
(too old to reply)
'Johannes Schaub' via ISO C++ Standard - Discussion
2017-06-10 17:35:55 UTC
Permalink
It is defined what it means to "copy" or to "move":

"A class object can be copied or moved in two ways: by
initialization ([class.ctor], [dcl.init]), including for function
argument passing ([expr.call]) and for function value return; and by
assignment."

Imagine this case:

class A {

};

class B {
public:
operator A();
};

And these two copies of a "B" object into an "A" object

B b;

A a1(b);
A a2 = b;

The case "a2" creates a temporary "A" in C+<17, and direct-initializes
the target object by this temporary. In C++17, the prvalue A returned
by the conversion function directly initializes A. So here, there is
no copy, respective an elided copy.

The case a1 however does not seem to allow copy-elision in C+<17:
There are two initializations: Direct-initialization of an "A" by a
"B", and copy-initialization of an "A&&" by a B. There is no
initialization of an A object by another A object, and therefore we
cannot elide a copy of an A temporary into an A object. C++17 requires
a copy here aswell, but it is quite clear in doing so. C+<17 however
is less clear.

Does everyone agree with my description for a1, that copy-elision is
not allowed? What do all the implementations do?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-06-10 18:17:24 UTC
Permalink
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
"A class object can be copied or moved in two ways: by
initialization ([class.ctor], [dcl.init]), including for function
argument passing ([expr.call]) and for function value return; and by
assignment."
class A {
};
class B {
operator A();
};
And these two copies of a "B" object into an "A" object
B b;
A a1(b);
A a2 = b;
The case "a2" creates a temporary "A" in C+<17, and direct-initializes
the target object by this temporary.
No, it copy-initializes the `a2` variable.
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
In C++17, the prvalue A returned
by the conversion function directly initializes A. So here, there is
no copy, respective an elided copy.
There are two initializations: Direct-initialization of an "A" by a
"B", and copy-initialization of an "A&&" by a B.
I'm not sure where you get "copy-initialization of an 'A&&' by a B" from. I
don't see a `&&` anywhere in that statement.

Let's follow the steps here. We attempt to perform direct initialization of
an `A` with an object of type `B`. Since `A` is a class type, we attempt to
call constructors. Well, there are no `A` constructors that take `B`, so
implicit conversions are considered.

`B` has an `operator A`, thus permitting an implicit conversion. So, we
call `B::operator A`, which results in a prvalue temporary of type `A`.
This prvalue temporary is then used to direct initialize the variable `a1`.

Well, if you have a prvalue of type `A`, and you use it to initialize an
object of type `A`, that is a copy/move operation. And therefore, it is
able to be elided.
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
There is no
initialization of an A object by another A object, and therefore we
cannot elide a copy of an A temporary into an A object. C++17 requires
a copy here aswell, but it is quite clear in doing so. C+<17 however
is less clear.
Does everyone agree with my description for a1, that copy-elision is
not allowed? What do all the implementations do?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
'Johannes Schaub' via ISO C++ Standard - Discussion
2017-06-10 21:10:46 UTC
Permalink
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
"A class object can be copied or moved in two ways: by
initialization ([class.ctor], [dcl.init]), including for function
argument passing ([expr.call]) and for function value return; and by
assignment."
class A {
};
class B {
operator A();
};
And these two copies of a "B" object into an "A" object
B b;
A a1(b);
A a2 = b;
The case "a2" creates a temporary "A" in C+<17, and direct-initializes
the target object by this temporary.
No, it copy-initializes the `a2` variable.
Not correct: "The call is used to direct-initialize, according to the
rules above, the object that is the destination of the
copy-initialization."
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
In C++17, the prvalue A returned
by the conversion function directly initializes A. So here, there is
no copy, respective an elided copy.
There are two initializations: Direct-initialization of an "A" by a
"B", and copy-initialization of an "A&&" by a B.
I'm not sure where you get "copy-initialization of an 'A&&' by a B" from. I
don't see a `&&` anywhere in that statement.
Let's follow the steps here. We attempt to perform direct initialization of
an `A` with an object of type `B`. Since `A` is a class type, we attempt to
call constructors. Well, there are no `A` constructors that take `B`, so
implicit conversions are considered.
`B` has an `operator A`, thus permitting an implicit conversion. So, we call
`B::operator A`, which results in a prvalue temporary of type `A`. This
prvalue temporary is then used to direct initialize the variable `a1`.
This simplified description doesn't capture how things work here: The
initialization of a1 is a call to constructors. And the conversion
function "operator A" is used to convert the "b" to the parameters of
the constructors. In particular, there is a move and a copy
constructor. One has parameter type "A const&" and the other has
parameter type "A&&" (which I was refering to). The move constructor
is selected because "operator A" -> "A&&" is better than "operator A"
-> "A const&" because "prvalue A -> A&&" is better than "prvalue A ->
A const&". That is why I said we have an copy-initialization of a
"A&&" by a B lvalue (because it's a function argument passing), and a
direct initialization of an "A" by a B lvalue (the toplevel
initialization), and why there is no initialization of an A by another
A.

It does not work as you described "the thing is not an A, so we first
convert to an A, and then direct-initialize the target with that A" -
that is exactly what *copy initialization* will do - i.e the a2 case,
but not the a1 case.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-06-11 03:40:21 UTC
Permalink
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
"A class object can be copied or moved in two ways: by
initialization ([class.ctor], [dcl.init]), including for function
argument passing ([expr.call]) and for function value return; and by
assignment."
class A {
};
class B {
operator A();
};
And these two copies of a "B" object into an "A" object
B b;
A a1(b);
A a2 = b;
The case "a2" creates a temporary "A" in C+<17, and direct-initializes
the target object by this temporary.
No, it copy-initializes the `a2` variable.
Not correct: "The call is used to direct-initialize, according to the
rules above, the object that is the destination of the
copy-initialization."
Fair enough.
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
In C++17, the prvalue A returned
by the conversion function directly initializes A. So here, there is
no copy, respective an elided copy.
There are two initializations: Direct-initialization of an "A" by a
"B", and copy-initialization of an "A&&" by a B.
I'm not sure where you get "copy-initialization of an 'A&&' by a B"
from. I
Post by Nicol Bolas
don't see a `&&` anywhere in that statement.
Let's follow the steps here. We attempt to perform direct initialization
of
Post by Nicol Bolas
an `A` with an object of type `B`. Since `A` is a class type, we attempt
to
Post by Nicol Bolas
call constructors. Well, there are no `A` constructors that take `B`, so
implicit conversions are considered.
`B` has an `operator A`, thus permitting an implicit conversion. So, we
call
Post by Nicol Bolas
`B::operator A`, which results in a prvalue temporary of type `A`. This
prvalue temporary is then used to direct initialize the variable `a1`.
This simplified description doesn't capture how things work here: The
initialization of a1 is a call to constructors. And the conversion
function "operator A" is used to convert the "b" to the parameters of
the constructors.
No, it does not. `B::operator A` is used to create a prvalue, which then
becomes the argument in a function call expression (specifically a call to
the move constructor). That function call is what initializes the parameter
with the argument prvalue.

If you elide the function call, then *by definition* you have elided the
initialization of that function's parameters. And therefore, you are left
with a prvalue of type `A`. Which thanks to copy elision, we now give the
name `a1`.

In particular, there is a move and a copy
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
constructor. One has parameter type "A const&" and the other has
parameter type "A&&" (which I was refering to). The move constructor
is selected because "operator A" -> "A&&" is better than "operator A"
-> "A const&" because "prvalue A -> A&&" is better than "prvalue A ->
A const&".
Allow me to put it a different way. We agree that it will attempt to call
the move constructor. And a call to the move constructor... can be *elided*,
if that call comes as the result of passing a prvalue to the constructor in
question. And it does; the result of `B::operator A` is a prvalue. If there
is no call to the move constructor, then there is no "prvalue A -> A&&"
either, since that operation is initializing a parameter for a function
call that is being elided.

Thus, we have the following steps:

1) implicit conversion of B into prvalue A
2) initializing the parameter of the move constructor call from the prvalue
of type A.
3) call the move constructor
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
when a temporary class object that has not been bound to a reference
(12.2) would be copied/moved to a class object with the same cv-unqualified
type, the copy/move operation can be omitted by constructing the temporary
object directly into the target of the omitted copy/move

Before performing step 2, the following are true:

I) We have a temporary class object.
II) This temporary class object "has not been bound to a reference"
III) If we complete steps 2 and 3, then the temporary will have been
"copied/moved to a class object with the same cv-unqualified type"

If all of those are true, then "the copy/move operation can be omitted by
constructing the temporary object directly into the target of the omitted
copy/move". And therefore elision can happen.

That is why I said we have an copy-initialization of a
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
"A&&" by a B lvalue (because it's a function argument passing), and a
direct initialization of an "A" by a B lvalue (the toplevel
initialization), and why there is no initialization of an A by another
A.
No, that breakdown of operations still doesn't make any sense. Even if we
allow this "`A&&` from B lvalue" thing, the next operation is not "direct
initialization" of anything; it's calling the move constructor with the
parameter you just initialized.

The entire process is "direct initialization of an `A` by a B lvalue". I'm
talking about the individual operations needed to carry out that process.

It does not work as you described "the thing is not an A, so we first
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
convert to an A, and then direct-initialize the target with that A" -
that is exactly what *copy initialization* will do - i.e the a2 case,
but not the a1 case.
But they *are the same*. That is, they result in the exact same sequence of
operations. Let's break down `a2`. As you said, "the case "a2" creates a
temporary "A" in C+<17, and direct-initializes the target object by this
temporary." So, the steps are:

1) implicit conversion of B into prvalue A
2) default initialize `a2` from a prvalue of type A.

Well, we know how step 2 breaks down. You call the move constructor,
initializing its parameter along the way. And therefore, the total steps
are:

1) implicit conversion of B into prvalue A
2) initializing the parameter of the move constructor call from the prvalue
of type A.
3) call the move constructor

The process of direct initialization doesn't *have* to result in different
operations from copy initialization. The way in which you figure out which
operations to do may be different, but the resulting operations in this
case are the same: convert the `B` into an `A` and use that to call a move
constructor.

That last part gets elided in both cases.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-06-11 03:42:20 UTC
Permalink
Post by Nicol Bolas
2) default initialize `a2` from a prvalue of type A.
I meant "direct initialize".
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
'Johannes Schaub' via ISO C++ Standard - Discussion
2017-06-11 06:42:04 UTC
Permalink
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
"A class object can be copied or moved in two ways: by
initialization ([class.ctor], [dcl.init]), including for function
argument passing ([expr.call]) and for function value return; and by
assignment."
class A {
};
class B {
operator A();
};
And these two copies of a "B" object into an "A" object
B b;
A a1(b);
A a2 = b;
The case "a2" creates a temporary "A" in C+<17, and direct-initializes
the target object by this temporary.
In C++17, the prvalue A returned
by the conversion function directly initializes A. So here, there is
no copy, respective an elided copy.
There are two initializations: Direct-initialization of an "A" by a
"B", and copy-initialization of an "A&&" by a B.
I'm not sure where you get "copy-initialization of an 'A&&' by a B" from. I
don't see a `&&` anywhere in that statement.
Let's follow the steps here. We attempt to perform direct initialization of
an `A` with an object of type `B`. Since `A` is a class type, we attempt to
call constructors. Well, there are no `A` constructors that take `B`, so
implicit conversions are considered.
`B` has an `operator A`, thus permitting an implicit conversion. So, we call
`B::operator A`, which results in a prvalue temporary of type `A`. This
prvalue temporary is then used to direct initialize the variable `a1`.
This simplified description doesn't capture how things work here: The
initialization of a1 is a call to constructors. And the conversion
function "operator A" is used to convert the "b" to the parameters of
the constructors.
No, it does not. `B::operator A` is used to create a prvalue, which then
becomes the argument in a function call expression (specifically a call to
the move constructor). That function call is what initializes the parameter
with the argument prvalue.
"argument" is defined as: "⟨function call expression⟩ expression in
the comma-separated list bounded by the parentheses ([expr.call])".
The expression is a "b" here, not the call to "operator A". That
implicit call is also an expression, but it is not the expression in
the comma-separated list bounded by the parentheses. Here our
arguments are "The constructor so selected is called to initialize the
object, with the initializer expression or expression-list as its
argument(s).".
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
In particular, there is a move and a copy
constructor. One has parameter type "A const&" and the other has
parameter type "A&&" (which I was refering to). The move constructor
is selected because "operator A" -> "A&&" is better than "operator A"
-> "A const&" because "prvalue A -> A&&" is better than "prvalue A ->
A const&".
Allow me to put it a different way. We agree that it will attempt to call
the move constructor. And a call to the move constructor... can be elided,
if that call comes as the result of passing a prvalue to the constructor in
question. And it does; the result of `B::operator A` is a prvalue. If there
is no call to the move constructor, then there is no "prvalue A -> A&&"
either, since that operation is initializing a parameter for a function call
that is being elided.
A call to the move constructor can in general not be elided. A copy or
move can be elided, which is an initialization or assignment. That
copy or move by coincidence may happen to call a copy or move
constructor, but that's not necessarily. The copy or move may also be
done by a template constructor or by an assignment operator. The call
to the constructor then is elided because it's a constituent of the
copy or move, just like a parameter initialization can be omitted if
you omit the corresponding function call.
Post by Nicol Bolas
1) implicit conversion of B into prvalue A
2) initializing the parameter of the move constructor call from the prvalue
of type A.
3) call the move constructor
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
when a temporary class object that has not been bound to a reference
(12.2) would be copied/moved to a class object with the same cv-unqualified
type, the copy/move operation can be omitted by constructing the temporary
object directly into the target of the omitted copy/move
I) We have a temporary class object.
II) This temporary class object "has not been bound to a reference"
III) If we complete steps 2 and 3, then the temporary will have been
"copied/moved to a class object with the same cv-unqualified type"
Well, the prvalue A is not copied or moved, but it will be used as the
argument (or conversion of the argument) in the call to the move
constructor. Since this move constructor call is part of the move of a
B object into an A object, rather than part of the move of a prvalue A
to a A object, we cannot elide it because it does not satisfy
[class.copy]/31.3 and the definition of "move" and "copy" (notice that
31.2 specifically uses these two terms, and not "would be used in the
argument of a constructor or assignment operator call").

Before performing step 2, we also have:

A) We want to call the move constructor in a move of a B lvalue
B) We construct an implicit conversion from the B lvalue to the A &&
parameter of the move constructor
C) => Gives us a temporary prvalue A
Post by Nicol Bolas
If all of those are true, then "the copy/move operation can be omitted by
constructing the temporary object directly into the target of the omitted
copy/move". And therefore elision can happen.
I agree, but III is not true.
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
That is why I said we have an copy-initialization of a
"A&&" by a B lvalue (because it's a function argument passing), and a
direct initialization of an "A" by a B lvalue (the toplevel
initialization), and why there is no initialization of an A by another
A.
No, that breakdown of operations still doesn't make any sense. Even if we
allow this "`A&&` from B lvalue" thing, the next operation is not "direct
initialization" of anything; it's calling the move constructor with the
parameter you just initialized.
The next initialization is the A&& by B lvalue. The entire process is
"direct initialization of an A by a B lvalue". This is what
constitutes the move/copy.
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
It does not work as you described "the thing is not an A, so we first
convert to an A, and then direct-initialize the target with that A" -
that is exactly what *copy initialization* will do - i.e the a2 case,
but not the a1 case.
But they are the same. That is, they result in the exact same sequence of
operations. Let's break down `a2`. As you said, "the case "a2" creates a
temporary "A" in C+<17, and direct-initializes the target object by this
1) implicit conversion of B into prvalue A
2) default initialize `a2` from a prvalue of type A.
Well, we know how step 2 breaks down. You call the move constructor,
initializing its parameter along the way. And therefore, the total steps
1) implicit conversion of B into prvalue A
2) initializing the parameter of the move constructor call from the prvalue
of type A.
3) call the move constructor
The process of direct initialization doesn't have to result in different
operations from copy initialization. The way in which you figure out which
operations to do may be different, but the resulting operations in this case
are the same: convert the `B` into an `A` and use that to call a move
constructor.
That last part gets elided in both cases.
An initialization means that you get to clause [dcl.init], which in
our case only happens twice: For the A object by a B lvalue ("A a(b)"
and for the "A&&" reference by the B lvalue by the constructor call).
The prvalue A thing happens in a subclause, deeply nested in
[dcl.init.ref]p5bOtherwisebIfbhas.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Nicol Bolas
2017-06-11 14:27:28 UTC
Permalink
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
A call to the move constructor can in general not be elided. A copy or
move can be elided, which is an initialization or assignment.
When certain criteria are met, an implementation is allowed to omit the *copy/move
construction* of a class object, even if the constructor selected for the
copy/move operation and/or the destructor for the object have side effects.

Note that this does not say that it is allowed to omit the "initialization
or assignment" of a class. It is allowed to omit the "copy/move
construction" of the class. So clearly, the target of the elision operator
is the call to the "copy/move construction" itself, *not* the
"initialization or assignment".

So your initial quote from [class.copy]/1, "A class object can be copied or
moved in two ways" is essentially irrelevant. Elision is about removing the
constructor call part of the copy/move, not the entirety of the copy/move.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
'Johannes Schaub' via ISO C++ Standard - Discussion
2017-06-11 15:16:56 UTC
Permalink
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
A call to the move constructor can in general not be elided. A copy or
move can be elided, which is an initialization or assignment.
When certain criteria are met, an implementation is allowed to omit the
copy/move construction of a class object, even if the constructor selected
for the copy/move operation and/or the destructor for the object have side
effects.
Note that this does not say that it is allowed to omit the "initialization
or assignment" of a class. It is allowed to omit the "copy/move
construction" of the class. So clearly, the target of the elision operator
is the call to the "copy/move construction" itself, not the "initialization
or assignment".
I do not understand. Do you say that "copy/move construction" means
something different than "construction by copy/move"? The additional
"construction" makes the text not apply to copy/moves by assignments.
That's the most direct interpretation, I think, because no bullet of
that paragraph allows elision in assignments, so it would not make
sense for the intro-text of the paragraph to include copy/moves by
assignments.
Post by Nicol Bolas
So your initial quote from [class.copy]/1, "A class object can be copied or
moved in two ways" is essentially irrelevant. Elision is about removing the
constructor call part of the copy/move, not the entirety of the copy/move.
The entirety of the copy/move is elided. Why would it not be? Can you
show an example where a copy/move elision, within the constraints
pointed out in the bullets of [class.copy]/31, does not elide the
entire copy/move but only part of it?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
'Johannes Schaub' via ISO C++ Standard - Discussion
2017-06-11 15:33:50 UTC
Permalink
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
A call to the move constructor can in general not be elided. A copy or
move can be elided, which is an initialization or assignment.
When certain criteria are met, an implementation is allowed to omit the
copy/move construction of a class object, even if the constructor selected
for the copy/move operation and/or the destructor for the object have side
effects.
Note that this does not say that it is allowed to omit the "initialization
or assignment" of a class. It is allowed to omit the "copy/move
construction" of the class. So clearly, the target of the elision operator
is the call to the "copy/move construction" itself, not the "initialization
or assignment".
I do not understand. Do you say that "copy/move construction" means
something different than "construction by copy/move"? The additional
"construction" makes the text not apply to copy/moves by assignments.
That's the most direct interpretation, I think, because no bullet of
that paragraph allows elision in assignments, so it would not make
sense for the intro-text of the paragraph to include copy/moves by
assignments.
Post by Nicol Bolas
So your initial quote from [class.copy]/1, "A class object can be copied or
moved in two ways" is essentially irrelevant. Elision is about removing the
constructor call part of the copy/move, not the entirety of the copy/move.
The entirety of the copy/move is elided. Why would it not be? Can you
show an example where a copy/move elision, within the constraints
pointed out in the bullets of [class.copy]/31, does not elide the
entire copy/move but only part of it?
Let me be more precise about the inquiry, to avoid misunderstandings.
Obviously we cannot remove the complete declaration, since we still
need to evaluate the initializer. So we can argue that only the extra
construction of the target variable is elided, by aliasing its object
with the source object. So, let's try to apply one of the bullets of
C++14, to see when we can apply copy/move-elision: "when a temporary
class object that has not been bound to a reference (12.2) would be
copied/moved to a class object with the same cv-unqualified type,".
This states that a temporary class object needs to be copied/moved to
a class object with the same cv-unqualified type: Since a copy is an
initialization(or assignment): "when a temporary class object ...
would be initialized to a class object with the same cv-unqualified
type": What else should that mean, other than that there needs to be
an initialization, with the source type being a certain type T and the
target type also being the same certain type T (ignoring
cv-qualifiers)? If this condition holds, then we can omit the
construction (the bullet even specifies in what sense the copy is
elided, what it means). But if it does not hold - when the source is B
and the target is A, then the copy/move construction can't be elided.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Tony V E
2017-06-11 15:40:05 UTC
Permalink
How do I summon Richard? Does it require penta‎grams?

I actually thought it only required email chains like this one, but obviously we are missing a chant or something.

Sent from my BlackBerry portable Babbage Device
  Original Message  
From: 'Johannes Schaub' via ISO C++ Standard - Discussion
Sent: Sunday, June 11, 2017 11:33 AM
To: std-***@isocpp.org
Reply To: std-***@isocpp.org
Subject: Re: [std-discussion] Re: Validity of copy-elision of return of conversion function, in direct-initialization
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
Post by Nicol Bolas
Post by 'Johannes Schaub' via ISO C++ Standard - Discussion
A call to the move constructor can in general not be elided. A copy or
move can be elided, which is an initialization or assignment.
When certain criteria are met, an implementation is allowed to omit the
copy/move construction of a class object, even if the constructor selected
for the copy/move operation and/or the destructor for the object have side
effects.
Note that this does not say that it is allowed to omit the "initialization
or assignment" of a class. It is allowed to omit the "copy/move
construction" of the class. So clearly, the target of the elision operator
is the call to the "copy/move construction" itself, not the "initialization
or assignment".
I do not understand. Do you say that "copy/move construction" means
something different than "construction by copy/move"? The additional
"construction" makes the text not apply to copy/moves by assignments.
That's the most direct interpretation, I think, because no bullet of
that paragraph allows elision in assignments, so it would not make
sense for the intro-text of the paragraph to include copy/moves by
assignments.
Post by Nicol Bolas
So your initial quote from [class.copy]/1, "A class object can be copied or
moved in two ways" is essentially irrelevant. Elision is about removing the
constructor call part of the copy/move, not the entirety of the copy/move.
The entirety of the copy/move is elided. Why would it not be? Can you
show an example where a copy/move elision, within the constraints
pointed out in the bullets of [class.copy]/31, does not elide the
entire copy/move but only part of it?
Let me be more precise about the inquiry, to avoid misunderstandings.
Obviously we cannot remove the complete declaration, since we still
need to evaluate the initializer. So we can argue that only the extra
construction of the target variable is elided, by aliasing its object
with the source object. So, let's try to apply one of the bullets of
C++14, to see when we can apply copy/move-elision: "when a temporary
class object that has not been bound to a reference (12.2) would be
copied/moved to a class object with the same cv-unqualified type,".
This states that a temporary class object needs to be copied/moved to
a class object with the same cv-unqualified type: Since a copy is an
initialization(or assignment): "when a temporary class object ...
would be initialized to a class object with the same cv-unqualified
type": What else should that mean, other than that there needs to be
an initialization, with the source type being a certain type T and the
target type also being the same certain type T (ignoring
cv-qualifiers)? If this condition holds, then we can omit the
construction (the bullet even specifies in what sense the copy is
elided, what it means). But if it does not hold - when the source is B
and the target is A, then the copy/move construction can't be elided.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussion+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.
Continue reading on narkive:
Loading...