In the Guidelines Support Library there is a class called final_action (essentially the well known ScopeGuard). There are 2 free-standing convenience functions to generate this templated class:
// finally() - convenience function to generate a final_action
template <class F>
inline final_action<F> finally(const F& f) noexcept
{
return final_action<F>(f);
}
template <class F>
inline final_action<F> finally(F&& f) noexcept
{
return final_action<F>(std::forward<F>(f));
}
What is the need for the first one? If we only had the second one (using the forwarding , a.k.a. universal, references) wouldn't it do the same thing?
Let's consider the perfectly-forwarding version:
When called with an rvalue, it will return
final_action<F>(static_cast<F&&>(f)).When called with an lvalue, it will return
final_action<F&>(f).Let's now consider the
const F&overload:final_action<F>(f).As you can see, there is an important difference:
Passing a non-
constlvalue reference tofinallywill produce a wrapper that stores aF&Passing a
constlvalue reference tofinallywill produce a wrapper that stores aFlive example on wandbox
I am not sure why it was deemed necessary to have the
const F&overload.This is the implementation of
final_action:Unless I am missing something, instanting
final_action<F&>doesn't really make sense, asf_(std::move(f))will not compile.live example on wandbox
So I think this should have just been:
Ultimately, I think that the implementation of
finallyin GSL incorrect/unoptimal (i.e. redundant, has code repetition).