I have the following two function template overloads:
template<typename T>
optional<T> some(const T& x)
{
return optional<T>(x);
}
template<typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, optional<T> >::type
some(T&& x)
{
return optional<T>(std::move(x));
}
My first attempt at unifying the overloads via perfect forwarding failed:
template<typename T>
optional<T> some(T&& x)
{
return optional<T>(std::forward<T>(x));
}
error: forming pointer to reference type 'const std::basic_string<char>&'
As did my second attempt:
template<typename T>
optional<typename std::remove_reference<T>::type> some(T&& x)
{
return optional<typename std::remove_reference<T>::type>(std::forward<T>(x));
}
error: no matching function for call to
'std::basic_string<char>::basic_string(gpa::optional<const std::basic_string<char> >)'
Is there a clean way to unify the overloads, or should I just live with having them?
I'm not familiar with your optional
, but perhaps you need to add:
typename remove_const< ... >::type
around your remove_reference
in two places. (because your 1st overload of your 2-overload solution - which I assume is passing all of your tests - effectively does a remove_const
when declaring optional<T>
).
In general, the best way to do this is to take the object by value and let the caller decide whether to copy or move it:
template<typename T>
optional<T> some(T x)
{
return optional<T>(std::move(x));
}
If the caller calls it with a temporary or uses std::move
on their value, then it's moved. Otherwise it's copied.
Yes, this does mean that you'll do one additional move (which, if movement is the same as copying, means doing two copies). If that's a significant performance problem for you, then you'll have to use the two overloads implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With