Question
Generic Perfect Forwarding of Function’s Result
I encountered an issue when trying to perfect forward a function’s result in a generic way.
Here two functions that provide a result:
Foo provideFooAsTemporary()
{
return Foo{};
}
Foo& provideFooAsReference()
{
static Foo foo{};
return foo;
}
Here the erroneous perfect forwarding:
template <typename TFn>
decltype(auto) erroneousForwardFoo(TFn&& fn)
{
auto&& result = fn();
// do some stuff here
return std::forward<decltype(result)>(result);
}
Foo fooTemporary = erroneousForwardFoo(provideFooAsTemporary); // fails
Foo& fooReference = erroneousForwardFoo(provideFooAsReference); // works
When the result is a temporary, the forwarding fails, which is indicated by the result from erroneousForwardFoo
pointing to invalid memory.
In contrast, the following simplified forwarding code works like a charm:
template <typename TFn>
decltype(auto) workingForwardFoo(TFn&& fn)
{
return fn();
}
Foo fooTemporary = workingForwardFoo(provideFooAsTemporary); // works
Foo& fooReference = workingForwardFoo(provideFooAsReference); // works
However, I want to "do some stuff" before returning, so I need a fix for erroneousForwardFoo
.
Debugging has shown that a dangling reference is the problem (see godbolt example). As I understand, this is because the lifetime of the temporary is bound to the rvalue reference result
, and unfortunately moving doesn’t change this.
Now the questions:
- What is the detailed and accurate explanation of what’s going wrong?
- How can I rewrite
erroneousForwardFoo
in a lean way to achieve a correct generic implementation?
EDIT 1: Although I only provided a code example for forwarding a lvalue reference, I want the solution to support rvalue references too:
Foo&& provideFooAsRValueReference()
{
static Foo foo{};
return std::move(foo);
}