Advice on std::forward
is generally limited to the canonical use case of perfectly forwarding function template arguments; some commentators go so far as to say this is the only valid use of std::forward
. But consider code like this:
// Temporarily holds a value of type T, which may be a reference or ordinary
// copyable/movable value.
template <typename T>
class ValueHolder {
public:
ValueHolder(T value)
: value_(std::forward<T>(value)) {
}
T Release() {
T result = std::forward<T>(value_);
return result;
}
private:
~ValueHolder() {}
T value_;
};
In this case, the issue of perfect forwarding does not arise: since this is a class template rather than a function template, client code must explicitly specify T
, and can choose whether and how to ref-qualify it. By the same token, the argument to std::forward
is not a "universal reference".
Nonetheless, std::forward
appears to be a good fit here: we can't just leave it out because it wouldn't work when T
is a move-only type, and we can't use std::move
because it wouldn't work when T
is an lvalue reference type. We could, of course, partially specialize ValueHolder
to use direct initialization for references and std::move
for values, but this seems like excessive complexity when std::forward
does the job. This also seems like a reasonable conceptual match for the meaning of std::forward
: we're trying to generically forward something that might or might not be a reference, only we're forwarding it to the caller of a function, rather than to a function we call ourselves.
Is this a sound use of std::forward
? Is there any reason to avoid it? If so, what's the preferred alternative?