dimanche 19 avril 2020

Is it possible to omit template parameter in `std::forward`?

The standard signature of std::forward is:

template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&) noexcept;
template<typename T>
constexpr T&& forward(std::remove_reference_t<T>&&) noexcept;

Because the parameter type isn't T directly, we should specify the template argument when using std::forward:

template<typename... Args>
void foo(Args&&... args)
{
    bar(std::forward<Args>(args)...);
}

However sometimes the template argument is not as simple as Args. auto&& is a case:

auto&& vec = foo();
bar(std::forward<decltype(vec)>(vec));

You can also imagine more complicated template argument types for std::forward. Anyway, intuitively std::forward should know what T is but it actually don't.

So my idea is to omit <Args> and <decltype(vec)> no matter how simple they are. Here is my implementation:

#include <type_traits>

template<typename T>
std::add_rvalue_reference_t<std::enable_if_t<!std::is_lvalue_reference<T>::value, T>>
my_forward(T&& obj)
{
    return std::move(obj);
}

template<typename T>
T& my_forward(T& obj)
{
    return obj;
}

int main()
{
    my_forward(1); // my_forward(int&&)
    int i = 2;
    my_forward(i); // my_forward(int&)
    const int j = 3;
    my_forward(j); // my_forward(const int&)
}

When obj is rvalue reference, for example int&&, the first overload is selected because T is int, whose is_lvalue_reference is false;

When obj is lvalue reference, for example const int&, the second overload is selected because T is const int& and the first is SFINAE-ed out.

If my implementation is feasible, why is std::forward still requiring <T>? (So mine must be infeasible.)

If not, what's wrong? And still the question, is it possible to omit template parameter in std::forward?

Aucun commentaire:

Enregistrer un commentaire