不了解左值的双重转发-按值传递时

时间:2018-06-22 15:14:00

标签: c++ c++11 rvalue-reference perfect-forwarding

#include <iostream>
#include <vector>
#include <type_traits>
#include <utility>

using namespace std;

template <typename Func, typename... Args>
void proxy(Func f, Args&&... args) {
    f(std::forward<Args>(args)...);
}

void real_func(vector<int> v) {
    cout << "size: " << v.size() << endl;
}

void multicast_func(vector<int> v) {
    proxy(real_func, std::forward<vector<int>>(v));
    proxy(real_func, std::forward<vector<int>>(v));
}

int main()
{
    vector<int> ints = {1, 2, 3};
    multicast_func(ints);
    return 0;
}

,输出为:

size: 3
size: 0

为什么不是3、3?在什么时候该左值变成右值并从中移出?

5 个答案:

答案 0 :(得分:5)

std::forward旨在与通用引用一起使用。

multicast_func的参数不是通用引用,因此std::forward毫无意义:

void multicast_func(vector<int> v) {
    proxy(real_func, std::forward<vector<int>>(v));
    proxy(real_func, std::forward<vector<int>>(v));
}

在这种情况下,它实际上像std::move一样工作(因为template参数不是(左值)引用)。

答案 1 :(得分:4)

您的代码中调用的std::forward的原型为:

template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type& t ) noexcept;

以非引用类型调用时,它有效地从参数中移出了右值引用,然后将其移出。 std::vector被确保从其移出后为空,因此size变为0。

答案 2 :(得分:1)

  

在什么时候该左值变成右值并从中移出?

第一次调用v时,real_func被转换为右值,然后在传递给void multicast_func(vector<int> v) { // the return type of std::forward is T&&, i.e. vector<int>&& here // for functions whose return type is rvalue reference to objec, the return value is an rvalue // that means v is converted to an rvalue and passed to proxy proxy(real_func, std::forward<vector<int>>(v)); // v has been moved when passed to real_func as argument proxy(real_func, std::forward<vector<int>>(v)); } 时被移出。

proxy

std::forward中的用法是T&的常规用法;根据参数是左值还是右值,模板参数将推导为TT&。对于std::forward T将返回一个左值,对于std::forward import { LitElement, html } from '../lib/@polymer/lit-element/lit-element.js'; 将返回一个右值,因此将保留值类别。当您指定模板参数时,仅会丢失这种容量。

答案 3 :(得分:1)

std::forward,如果未指定引用类型,则会将提供的对象转换为右值。这意味着第一个呼叫

proxy(real_func, std::forward<vector<int>>(v));

将使v成为右值,这意味着它将把它移到real_func中。然后,第二个调用使用从对象移出的那个,您会得到0的大小,因为它已被清空。

如果我们看一下函数,这是有道理的。您正在呼叫的std::forward的版本是

template< class T >
constexpr T&& forward( typename std::remove_reference<T>::type& t ) noexcept;

由于您为std::vector<int>传递了T,这意味着它将返回一个std::vector<int>&&。因此,即使v是左值,它也会转换为右值。如果要保持v的左值性,则需要使用std::vector<int>&。这样就给了std::vector<int>& &&,引用折叠规则将其变成std::vector<int>&,使您拥有左值。

答案 4 :(得分:0)

proxy的第一次调用中,参数vector<int> v(在函数real_func中)是从右值构造的,因此v(在函数{{1}中) })为空。
但是,如果将参数的类型更改为multicast_func,则结果将为3、3。因为尚未调用move constrctor。

cosnt vector<int> &