【问题标题】:Why is std::forward needed, can't the compiler do the correct thing by default [duplicate]为什么需要std :: forward,默认情况下编译器不能做正确的事情[重复]
【发布时间】:2017-08-24 14:03:23
【问题描述】:

std::forward 是一个条件转换,为什么当编译器看到用户试图传递给其他函数的参数是通用引用时,它不能自动完成工作。

意味着为什么编译器会将做正确事情的责任放在用户身上,写成std::forward

以有效的现代 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”,而是为什么编译器默认情况下不能做明显的事情,即在传递转发引用时调用正确的函数重载around ,包括检测多次使用和在最后一次使用时转换为右值。

【问题讨论】:

  • 默认行为更安全。假设我想在logAndProcess 中呼叫process 两次。如果您遗漏了std::forwardparam 将被复制。相反,如果行为是您想要的,那么对process 的第二次调用将有一个param,它可能已从第一次调用process 移出。此外,通用引用现在称为转发引用
  • @Praetorian ,所以如果你使用 std::forward 你确定第二次使用是否安全?我的意思是即使使用 std::forward 你也不知道参数发生了什么,无论它是被移动还是复制,因为你不知道函数是如何被左值或右值调用的。
  • @user8063157 - 不。但是如果默认情况下总是移动右值,你只能使用它们一次,然后它们就消失了。现在你必须用std::movestd::forward 明确标记你的最后一次使用,让它们“继续”。
  • @Bopersson ,最后与 std::forward 一起使用不会对 In between calls 造成不公正,哪个会复制?话虽如此,编译器还可以检测最后一次使用转发引用的时间并做正确的事情!
  • 正确的是什么?也许在我展示的示例中,我希望对process 的第一次调用有条件地从param 移动,并且我有一些方法可以在第二次调用中检测到它并采取相应的行为。所以在第一种情况下复制并在第二种情况下转发不是我想要的。编译器无法读懂程序员的想法,因此正常的默认设置是在所有情况下都以安全的方式行事,除非另有说明。

标签: c++ c++11 std forward


【解决方案1】:

作为命名参数,param 始终是左值。这意味着没有std::forwardprocess(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

【讨论】:

    猜你喜欢
    • 2016-03-04
    • 2014-02-25
    • 2015-02-11
    • 2023-03-03
    • 1970-01-01
    • 2011-09-17
    • 2017-07-08
    • 1970-01-01
    • 2018-06-04
    相关资源
    最近更新 更多