Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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>).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top