Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is std::forward needed, can't the compiler do the correct thing by default [duplicate]

With std::forward being a conditional cast, why can't the compiler do the work automatically when it sees the parameter which user is trying to pass to other function came as Universal reference.

Means why compiler will place the onus of doing right thing on user by way of writing std::forward.

Taking example from Effective modern C++.

void process(const Widget& lvalArg); // process lvalues
void process(Widget&& rvalArg); // process rvalues

template<typename T> // template that passes
void logAndProcess(T&& param) // param to process
{
    auto now = // get current time
    std::chrono::system_clock::now();
    makeLogEntry("Calling 'process'", now);
    process(std::forward<T>(param));
}

In above code sample I know removing std::forward will choose the incorrect overload for process , but to do the right thing of choosing correct overload why user need to write std::forward, I mean can't compiler do the obvious for us and for user who don't want to do the correct thing , we can have std::dont_forward instead.

I might be missing some use case where compiler can be confused to what's correct but in above case where param being universal reference and two overload of process given to compiler I don't see any confusion.

Just to explain how this question is diffrent that its not about why we need 'std::forward' in current compiler behaviour but why cant compiler do the obvious by default that is to call correct overload of function when forwarding reference is passed around , including detection of multiple use and casting to rvalue on last use.

like image 263
user8063157 Avatar asked Sep 11 '25 14:09

user8063157


1 Answers

As a named parameter, param is always an lvalue. That means without std::forward, process(param); will always call the lvalue overload.

On the other hand, you need to tell the compiler when you want to convert it to rvalue explicitly; the compiler can't make the decision for you. e.g.

process(param);                  // you don't want param to be passed as rvalue and thus might be moved here
...
process(std::forward<T>(param)); // it's fine to be moved now
like image 79
songyuanyao Avatar answered Sep 13 '25 06:09

songyuanyao