Date: Thu, 10 Apr 2025 13:16:25 +0300
On 10 Apr 2025 11:53, Frederick Virchanza Gotham via Std-Proposals wrote:
>
> So if trigraph references were to be adopted into the Standard, we
> would give compiler writers some time to implement them. Then after a
> few years, we could go further with it, and specify that the compiler
> must automatically improvise the branching -- specifically what I'm
> saying here is that when the compiler encounters the following code:
>
> template<typename T>
> bool ProcessNode(T &&&arg) // Trigraph for automatic forwarding
> {
> NormaliseNode (arg);
> DistributeNode(arg);
>
> if ( NodeManager::mode != NodeManager::ModeAssimilate ) return;
>
> AssimilateNode(arg);
> }
>
> then it must treat it as though it were written:
>
> template<typename T>
> bool ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
>
> if ( NodeManager::mode == NodeManager::ModeAssimilate )
> {
> DistributeNode( arg );
> AssimilateNode( forward<T>(arg) );
> }
> else
> {
> DistributeNode( forward<T>(arg) );
> }
> }
This transformation may affect correctness and ABI (e.g. when
DistributeNode is a template that gets instantiated on a reference
argument type before the transformation and a non-reference type after).
I don't think this would be acceptable.
On the whole general idea, I don't see much benefit. You're effectively
saving typing one std::forward call per branch (which is often one), and
in exchange make the forwarding rules more obscure. It's not clear what
the "last mention" means, exactly. For example, do these count as
"mentions" and are these eligible to implicit forwarding?
ProcessNodePtr(&arg);
ProcessNodeRef(*&arg);
arg.NodeMethod();
if (arg1 == arg2) // user-defined operator==
...
arg = x;
DistributeNode(arg); // does this still forward after assignment?
There probably are other dubious use cases. I think, I would rather
prefer to be explicit about when a move is allowed to happen.
>
> So if trigraph references were to be adopted into the Standard, we
> would give compiler writers some time to implement them. Then after a
> few years, we could go further with it, and specify that the compiler
> must automatically improvise the branching -- specifically what I'm
> saying here is that when the compiler encounters the following code:
>
> template<typename T>
> bool ProcessNode(T &&&arg) // Trigraph for automatic forwarding
> {
> NormaliseNode (arg);
> DistributeNode(arg);
>
> if ( NodeManager::mode != NodeManager::ModeAssimilate ) return;
>
> AssimilateNode(arg);
> }
>
> then it must treat it as though it were written:
>
> template<typename T>
> bool ProcessNode(T &&arg)
> {
> NormaliseNode(arg);
>
> if ( NodeManager::mode == NodeManager::ModeAssimilate )
> {
> DistributeNode( arg );
> AssimilateNode( forward<T>(arg) );
> }
> else
> {
> DistributeNode( forward<T>(arg) );
> }
> }
This transformation may affect correctness and ABI (e.g. when
DistributeNode is a template that gets instantiated on a reference
argument type before the transformation and a non-reference type after).
I don't think this would be acceptable.
On the whole general idea, I don't see much benefit. You're effectively
saving typing one std::forward call per branch (which is often one), and
in exchange make the forwarding rules more obscure. It's not clear what
the "last mention" means, exactly. For example, do these count as
"mentions" and are these eligible to implicit forwarding?
ProcessNodePtr(&arg);
ProcessNodeRef(*&arg);
arg.NodeMethod();
if (arg1 == arg2) // user-defined operator==
...
arg = x;
DistributeNode(arg); // does this still forward after assignment?
There probably are other dubious use cases. I think, I would rather
prefer to be explicit about when a move is allowed to happen.
Received on 2025-04-10 10:16:28