On Monday, October 20, 2025, Andre Kostur wrote:
Your example doesn’t follow your premise. You suggested that you could do this by only declaring this ‘prvalue’ type, yet you had to modify Func in order to use it.
'Func' doesn't need to be modified. When I wrote the following:
template<typename T>
void Func(T &&arg)
{
T var( arg() );
}
I was showing how the compiler would implement it under the hood. Specifically, on x86_64 Linux, rather than the RDI register containing the address of an object of type T, it would instead contain the address of a function that returns a T by value.
Also in my previous post, I showed a compiler-generated function:
string CompilerGenerated000(void)
{
return SomeLibraryFunction( 8, 34.4 );
}
But of course the problem with this is the lifetimes of the arguments (i.e. 8, 34.4). There's no problem in this specific snippet because they are intrinsics, but we'd have a problem if they were more complicated, specifically if they were generated from local variables in 'main':
int main(int argc, char **argv)
{
SomeClass var( argc );
prvalue x = SomeLibraryFunction( var );
Func(x);
}
I think the way to deal with this is for the original template function:
template<typename T>
void Func(T &&arg)
{
T var( std::forward<T>(arg) );
}
to be implemented by the compiler as though it were:
template<typename T>
void Func( T (*pf)(int,double), int &&arg1, double &&arg2 )
{
T var( pf(arg1, arg2) );
}
and to do away with the 'prvalue' keyword altogether so that 'main' would then simply become:
int main(int argc, char **argv)
{
SomeClass var( argc );
Func( SomeLibraryFunction(var) );
}
So then all you have to do is upgrade your compiler and hit "Rebuild" on code written 5 years ago, and the compiler gets rid of redundant copy/move operations, instead allowing a function to take a PRvalue as an argument. This would also allow us in some instances to use classes that are both uncopyable and unmoveable (such as std::lock_guard).