C++ 将std::forward与非转发的普通旧引用一起使用

C++ 将std::forward与非转发的普通旧引用一起使用,c++,c++11,move-semantics,perfect-forwarding,C++,C++11,Move Semantics,Perfect Forwarding,询问朋友: 为什么以下代码中的std::forward将参数c强制转换为右值 template <typename T> void f (T& c) { using value_type = typename std::remove_reference_t<T>; std::vector<value_type> v; // debugger reveals: push_back( T&& value ) is

询问朋友:

为什么以下代码中的
std::forward
将参数
c
强制转换为右值

template <typename T>
void f (T& c) {
    using value_type = typename std::remove_reference_t<T>; 
    std::vector<value_type> v; 
    // debugger reveals: push_back( T&& value ) is called here  
    v.push_back(std::forward<T>(c));
}
模板
f区(T&c){
使用value\u type=typename std::remove\u reference\t;
std::向量v;
//调试器显示:这里调用push_back(T&&value)
v、 向后推(标准:向前推(c));
}

请注意,
c
在这里不是通用/转发参考。我知道,如果这个函数真的有用的话,它很可能会有更多的用处,但仍然很奇怪。

嗯,
std::forward(x)
的定义是将
x
转换成
T&
。如果您将一个非引用作为参数传递,您将返回一个右值引用
T&
。由于您的
T
不能是引用类型(您不能有对引用的引用),因此它必须是非引用类型。

嗯,
std::forward(x)
的定义是将
x
转换为type
T&
。如果您将一个非引用作为参数传递,您将返回一个右值引用
T&
。由于您的
T
不能是引用类型(您不能有对引用的引用),因此它必须是非引用类型。

std::forward(c)
相当于
static\u cast(c)

如果
T&
是一个转发引用,则这允许将左值作为左值转发,因为
T
将被推断为左值引用类型,并且
T&
将通过引用折叠规则成为相同的左值引用类型。在您的情况下,
T&
不是转发引用,因此这不起作用。

std::forward(c)
相当于
static\u cast(c)


如果
T&
是一个转发引用,则这允许将左值作为左值转发,因为
T
将被推断为左值引用类型,并且
T&
将通过引用折叠规则成为相同的左值引用类型。在您的情况下,
T&&
不是转发引用,因此这不起作用。

要理解这种情况,您必须理解转发引用起作用的原因。给出了这样的定义

template <typename T>
void foo(T&& t) {}
模板演绎将
T
演绎成
某种类型&
。现在参数
t
的类型为
some\u type&&
。由于不能引用引用,因此会应用规则,并将
some\u type&&&&
折叠为
some\u type&

如果你写的是

some_type some_object;
foo(some_object);
some_type some_object;
foo(std::move(some_object));
模板演绎将
T
演绎成
某种类型
。现在参数
t
的类型为
some\u type&
。这是一个完全有效的类型,因此没有进行引用折叠

现在我们进入
std::forward
。所有的
std::forward
都将其参数强制转换为
U&
。如果
U
some\U-type
,如上面第二种情况,参数将转换为
some\U-type&
。它仍然是一个右值引用。如果
U
some\U-type&
,如上述第一种情况,将再次执行引用折叠,并且
some\U-type&&
变为
some\U-type&
。所以
std::forward
返回一个左值引用


因此,原始问题的最终答案是
std::forward
的返回类型仅取决于作为
std::forward
的模板参数传递的类型。由于在您的情况下,
T
将始终被推断为非引用类型,
std::forward
将始终返回一个右值引用。

要理解这种情况,您必须理解转发引用工作的原因。给出了这样的定义

template <typename T>
void foo(T&& t) {}
模板演绎将
T
演绎成
某种类型&
。现在参数
t
的类型为
some\u type&&
。由于不能引用引用,因此会应用规则,并将
some\u type&&&&
折叠为
some\u type&

如果你写的是

some_type some_object;
foo(some_object);
some_type some_object;
foo(std::move(some_object));
模板演绎将
T
演绎成
某种类型
。现在参数
t
的类型为
some\u type&
。这是一个完全有效的类型,因此没有进行引用折叠

现在我们进入
std::forward
。所有的
std::forward
都将其参数强制转换为
U&
。如果
U
some\U-type
,如上面第二种情况,参数将转换为
some\U-type&
。它仍然是一个右值引用。如果
U
some\U-type&
,如上述第一种情况,将再次执行引用折叠,并且
some\U-type&&
变为
some\U-type&
。所以
std::forward
返回一个左值引用


因此,原始问题的最终答案是
std::forward
的返回类型仅取决于作为
std::forward
的模板参数传递的类型。由于在您的情况下,
T
将始终被推断为非引用类型,
std::forward
将始终返回一个右值引用。

“请注意,这里的c不是通用/转发引用。”那么为什么要使用
std::forward
?我无意中省略了一个符号and,只是想知道为什么std::forward的行为方式与这里相同。“请注意,这里的c不是通用/转发引用。”那么你为什么要使用
std::forward
?我不小心漏掉了一个符号,我只是想知道为什么std::forward的行为与这里一样。被认为是最详细的答案。被认为是最详细的答案。