Date: Fri, 2 Sep 2022 12:30:18 +0200
On 02/09/2022 09.49, Schneider, Robert wrote:
> Awesome, thank you very much both for the insights and the bug report!
>
> I'm still a bit confused how the current wording applies to theses cases. To me, it looks like it was written before mandatory copy elision. In fact, both gcc and clang refuse the example in pre-C++17 modes (-std=c++14).
>> When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]).
>
> Regarding "the constructor selected for the copy-initialization", before mandatory copy elision, that would have been a copy/move ctor to initialize the thrown object from the temporary object, except that the copy/move was then elided. But with mandatory copy elision, the only constructor used in my example is the default constructor. I think that's why gcc and clang refuse the example in pre-C++17 modes.
Yes.
> Similarly, "the constructor selected for a copy-initialization considering the thrown object as an lvalue" makes complete sense to me if we have a temporary and then copy-initialize the thrown object from it. But without the temporary (i.e., with mandatory copy elision), which object or expression am I to consider as an lvalue?
I agree with your analysis: The first "constructor selected"
might not actually exist given mandatory copy elision.
Maybe we should not say anything about it here and just rely
on the usual rules.
The reason for the "considered as an lvalue" phrasing is
the need to support std::exception_ptr on platforms that
don't do reference-counted exceptions. They may want to
copy the exception object when a std::exception_ptr gets
created or copied. At that point, the exception object
is type-erased, thus we need to capture and type-erase
the copy constructor when throwing the exception.
Jens
> Awesome, thank you very much both for the insights and the bug report!
>
> I'm still a bit confused how the current wording applies to theses cases. To me, it looks like it was written before mandatory copy elision. In fact, both gcc and clang refuse the example in pre-C++17 modes (-std=c++14).
>> When the thrown object is a class object, the constructor selected for the copy-initialization as well as the constructor selected for a copy-initialization considering the thrown object as an lvalue shall be non-deleted and accessible, even if the copy/move operation is elided ([class.copy.elision]).
>
> Regarding "the constructor selected for the copy-initialization", before mandatory copy elision, that would have been a copy/move ctor to initialize the thrown object from the temporary object, except that the copy/move was then elided. But with mandatory copy elision, the only constructor used in my example is the default constructor. I think that's why gcc and clang refuse the example in pre-C++17 modes.
Yes.
> Similarly, "the constructor selected for a copy-initialization considering the thrown object as an lvalue" makes complete sense to me if we have a temporary and then copy-initialize the thrown object from it. But without the temporary (i.e., with mandatory copy elision), which object or expression am I to consider as an lvalue?
I agree with your analysis: The first "constructor selected"
might not actually exist given mandatory copy elision.
Maybe we should not say anything about it here and just rely
on the usual rules.
The reason for the "considered as an lvalue" phrasing is
the need to support std::exception_ptr on platforms that
don't do reference-counted exceptions. They may want to
copy the exception object when a std::exception_ptr gets
created or copied. At that point, the exception object
is type-erased, thus we need to capture and type-erase
the copy constructor when throwing the exception.
Jens
Received on 2022-09-02 10:30:23