Date: Sat, 9 Mar 2024 22:37:13 +0000
On Sat, Mar 9, 2024 at 10:14 PM Jens Maurer wrote:
>
> Regarding the core language change: We generally don't special-case
> library types in the core language, unless the library types are
> needed for implementation of a core language feature (e.g.
> std::initializer_list).
I know, it's better to have total separation between language and
library, but this is an instance in which cooperation is necessary
between the two.
> Also, the wording uses "shall", causing the situation to be ill-formed.
I don't want the code to be ill-formed. I was more so aiming for
something along the lines of SFINAE i.e., instead of the compiler
failing, I want it to try find another way of compiling it. I'm not
sure what terminology to use to write that in English in the standard.
> Also, I don't understand how template argument deduction should
> work for the AwkwardClass constructor shown in the paper.
> What's the value of the Args... template parameter type, and
> how do the rules achieve that result?
Here's the code copy-pasted:
class AwkwardClass {
std::mutex m; // cannot move, cannot copy
public:
template<typename T>
AwkwardClass(T &&arg) noexcept
{
std::printf("T = %s\n", typeid(T).name());
}
};
AwkwardClass ReturnAwkwardClass(int const arg)
{
return AwkwardClass(arg);
}
void Func(void)
{
std::optional<AwkwardClass> var;
var.emplace( std::elide(ReturnAwkwardClass, -1) );
}
The invocation of the function "std::elide" returns a prvalue of type
"elide_t< . . . >", and this object is passed by Rvalue reference to
'std::optional::emplace'. Inside the implementation of 'emplace', we
have the following line:
::new(buffer) T( forward<Params>(args)... );
which after substitution becomes:
::new(buffer) T( std::elide_t< . . . >( . . . ) );
Without the change to the core language, the constructor belonging to
'AwkwardClass' will have its template parameter T set to
'std::elide_t< . . . >', but this is not what we want. With the core
language change, std::elide_t< . . . > cannot be substituted in for T
because constructors aren't allowed to have any parameter that is a
specialisation of std::elide_t, and so the compiler continues looking
for a way to compile it -- and the next thing it tries to do is find a
conversion operator, and it finds a conversion operator to go from
std::elide_t< . . . >( . . . ) to AwkwardClass, so we're left with:
::new(buffer) AwkwardClass( AwkwardClass() );
and because it's a PRvalue, all of the copy/move operations are elided.
>
> Regarding the core language change: We generally don't special-case
> library types in the core language, unless the library types are
> needed for implementation of a core language feature (e.g.
> std::initializer_list).
I know, it's better to have total separation between language and
library, but this is an instance in which cooperation is necessary
between the two.
> Also, the wording uses "shall", causing the situation to be ill-formed.
I don't want the code to be ill-formed. I was more so aiming for
something along the lines of SFINAE i.e., instead of the compiler
failing, I want it to try find another way of compiling it. I'm not
sure what terminology to use to write that in English in the standard.
> Also, I don't understand how template argument deduction should
> work for the AwkwardClass constructor shown in the paper.
> What's the value of the Args... template parameter type, and
> how do the rules achieve that result?
Here's the code copy-pasted:
class AwkwardClass {
std::mutex m; // cannot move, cannot copy
public:
template<typename T>
AwkwardClass(T &&arg) noexcept
{
std::printf("T = %s\n", typeid(T).name());
}
};
AwkwardClass ReturnAwkwardClass(int const arg)
{
return AwkwardClass(arg);
}
void Func(void)
{
std::optional<AwkwardClass> var;
var.emplace( std::elide(ReturnAwkwardClass, -1) );
}
The invocation of the function "std::elide" returns a prvalue of type
"elide_t< . . . >", and this object is passed by Rvalue reference to
'std::optional::emplace'. Inside the implementation of 'emplace', we
have the following line:
::new(buffer) T( forward<Params>(args)... );
which after substitution becomes:
::new(buffer) T( std::elide_t< . . . >( . . . ) );
Without the change to the core language, the constructor belonging to
'AwkwardClass' will have its template parameter T set to
'std::elide_t< . . . >', but this is not what we want. With the core
language change, std::elide_t< . . . > cannot be substituted in for T
because constructors aren't allowed to have any parameter that is a
specialisation of std::elide_t, and so the compiler continues looking
for a way to compile it -- and the next thing it tries to do is find a
conversion operator, and it finds a conversion operator to go from
std::elide_t< . . . >( . . . ) to AwkwardClass, so we're left with:
::new(buffer) AwkwardClass( AwkwardClass() );
and because it's a PRvalue, all of the copy/move operations are elided.
Received on 2024-03-09 22:37:23