为什么 'const int ci = 2;std::forward<int>(ci);' 工作以及如何修复/解决它?

Why doesn't `const int ci = 2; std::forward<int>(ci);` work and how to fix / workaround it?

本文关键字:int ci 何修复 工作 解决 lt const std forward gt 为什么      更新时间:2023-10-16

简单的问题,为什么下面不能工作(暗示复制ci)?

#include <utility>
int main(){
  const int ci = 2;
  std::forward<int>(ci);
}

prog.cpp: In function 'int main()':
Prog.cpp:6:23:错误:没有匹配的函数调用'forward(const int&)'

这个问题在写一些模板的时候出现了,我有一个简单的holder类型,如下所示。为了避免不必要的复制,我尽可能使用完美转发,但这似乎是问题的根源。

template<class T>
struct holder{
    T value;
    holder(T&& val)
        : value(std::forward<T>(val))
    {}
};
template<class T>
holder<T> hold(T&& val){
    // T will be deduced as int, because literal `5` is a prvalue
    // which can be bound to `int&&`
    return holder<T>(std::forward<T>(val));
}
template<class T>
void foo(holder<T> const& h)
{
    std::tuple<T> t;  // contrived, actual function takes more parameters
    std::get<0>(t) = std::forward<T>(h.value); // h.value is `const T`
}
int main(){
    foo(hold(5));
}

如果需要进一步的信息,请告诉我。

This:

#include <utility>
int main(){
  const int ci = 2;
  std::forward<int>(ci);
}

不起作用,因为您不能隐式地丢弃conststd::forward<T>(u)应读作:

u转发为T

你想说:

Forward an lvalue `const int` as an rvalue `int`.

会丢弃const。为了避免丢弃const,您可以:

#include <utility>
int main(){
  const int ci = 2;
  std::forward<const int>(ci);
}

说:

Forward an lvalue `const int` as an rvalue `const int`.

在你的代码中:

template<class T>
void foo(holder<T> const& h)
{
    std::tuple<T> t;  // contrived, actual function takes more parameters
    std::get<0>(t) = std::forward<T>(h.value); // h.value is `const T`
}

h上的const限定符影响数据成员选择表达式h.valueh.valueconst的左值int。您可以使用forward将其更改为const右值int,或者您可以使用forward将其原样传递(作为const左值int)。甚至可以使用forward来添加volatile(尽管我想不出一个好的理由)。

在您的示例中,我认为根本没有理由使用forward(除非您将consth中取出)。

    std::get<0>(t) = h.value; // h.value is `const T`

你的评论仍然是正确的。

这是一个枯燥的阅读,但是N2951调查了你可以和不可以用forward做什么以及为什么。在标准化之前,N3143对其进行了修改,但在最终的N3143配方中,用例和基本原理仍然有效且不变。

forward:

  • 可以将左值转发为左值
  • 可以将左值转发为右值
  • 可以将右值作为右值转发。
  • 可以将不符合cv条件的表达式转发给符合cv条件的表达式。
  • 可以将派生类型的表达式转发到可访问的、明确的基类型。

可以使用forward:

做的事情
  • 不能将右值作为左值转发。
  • 不能转发更多符合cv条件的表达式给更少符合cv条件的表达式。
  • 您不能转发任意类型转换(例如将int转发为double)。