I have a function whose return type is a simple generic lambda expression. (The lambda returned by this function is eventually passed as an argument to STL algorithms like std::transform()
or std::accumulate()
.)
When the lambda does not have an explicit return type, the compiler emits no warnings:
inline auto AccumulateInto() {
return [](const auto& src, const auto& dst) {return dst + src; };
}
When the lambda has an explicit return type specified:
inline auto AccumulateInto() {
return [](const auto& src, const auto& dst) -> decltype(dst) {return dst + src; };
}
both compilers emit these similar warnings:
GCC: returning reference to temporary [-Wreturn-local-addr]
MSVC: returning address of a local variable or temporary
Should this warning be heeded because it indicates a shortcoming in the approach (possible undefined behavior!) and should be refactored? or are they "noise"?
I can't determine why specifying the return type explicitly would cause the returned expression to be a "temporary" when it wouldn't be otherwise. Please explain, thanks!
EDIT (to add more context):
The desire to use auto
arguments to the lambda is that src
and dst
might be different types (e.g. one is std::uint8_t
and one is std::uint_16t
), but I want the return to ALWAYS be the same type as the dst
argument, regardless of the type of src
.
The point is that decltype(dst)
is auto const &
(where you can see auto
as a template type`, so the lambda return a reference (I repeat: a reference) to a constant object.
The problem is that is a reference to
dst + src
that is: a reference to a temporary value, the temporary object created from the operation dst + src
, that doesn't exist anymore when the lambda conclude the execution.
A possible solution: remove -> decltype(dst)
or change it to -> decltype(dst+src)
, so you return a value, not a reference.
Another way (require more typewriting in this case but can be prefereble in more complex cases) could be remove the reference part from the type returned from decltype()
.
So
-> std::remove_reference_t<decltype(dst)>
or, as suggested by Jarod42, also
-> std::decay_t<decltype(dst)>
If the type of dst
support the unary operator +
(returning the same type of dst
), another simple solution can be
-> decltype(+dst)
This way, +dst
is an expression, not a variable, so decltype(+dst)
isn't a reference anymore.