为什么需要 std::forward,默认情况下编译器不能做正确的事情
Why is std::forward needed, can't the compiler do the correct thing by default
由于 std::forward
是条件转换,为什么编译器在看到用户试图传递给其他函数的参数作为通用引用时不能自动完成工作。
意味着为什么编译器会通过编写 std::forward
.
的方式将做正确事情的责任放在用户身上
以 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));
}
在上面的代码示例中,我知道删除 std::forward
将为 process 选择不正确的重载,但是为了选择正确的重载做正确的事情,为什么用户需要写 std::forward
,我的意思是不能'编译器为我们和不想做正确事情的用户做了显而易见的事情,我们可以用 std::dont_forward
代替。
我可能遗漏了一些用例,在这些用例中,编译器可能会混淆什么是正确的,但在上述情况下,param 是通用引用,并且为编译器提供了两个进程重载,我没有看到任何混淆。
只是为了解释这个问题有何不同,它不是关于为什么我们在当前编译器行为中需要 'std::forward',而是为什么编译器不能默认执行明显的操作,即在转发引用时调用正确的函数重载是传递,包括检测多次使用并在最后一次使用时转换为右值。
作为命名参数,param
始终是左值。这意味着如果没有 std::forward
,process(param);
将始终调用左值重载。
另一方面,你需要明确地告诉编译器什么时候你想把它转换成右值;编译器无法为您做出决定。例如
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
由于 std::forward
是条件转换,为什么编译器在看到用户试图传递给其他函数的参数作为通用引用时不能自动完成工作。
意味着为什么编译器会通过编写 std::forward
.
以 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));
}
在上面的代码示例中,我知道删除 std::forward
将为 process 选择不正确的重载,但是为了选择正确的重载做正确的事情,为什么用户需要写 std::forward
,我的意思是不能'编译器为我们和不想做正确事情的用户做了显而易见的事情,我们可以用 std::dont_forward
代替。
我可能遗漏了一些用例,在这些用例中,编译器可能会混淆什么是正确的,但在上述情况下,param 是通用引用,并且为编译器提供了两个进程重载,我没有看到任何混淆。
只是为了解释这个问题有何不同,它不是关于为什么我们在当前编译器行为中需要 'std::forward',而是为什么编译器不能默认执行明显的操作,即在转发引用时调用正确的函数重载是传递,包括检测多次使用并在最后一次使用时转换为右值。
作为命名参数,param
始终是左值。这意味着如果没有 std::forward
,process(param);
将始终调用左值重载。
另一方面,你需要明确地告诉编译器什么时候你想把它转换成右值;编译器无法为您做出决定。例如
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