通用参考l值不复制对象

时间:2020-06-20 00:41:57

标签: c++ c++11 move-semantics lvalue forwarding-reference

为什么这些断言适用于以下代码?通用引用应绑定到左值引用var express = require("express"); var app = express(); var body = require("body-parser"); var https = require("https"); app.get("/results", function (req, res) { https.get("https://www.omdbapi.com/?apikey=d49698c3&s=harry", function (response) { response.on("data", function (data) { var got = JSON.parse(data); res.send(got.Title); }) }) }); ,并从run(T& a)复制对象b。但是,a函数中两个对象地址“ a”和“ b”相同。使用C ++ 11/14/17 / 2a gcc-9.2和clang ++-6.0进行了测试。标准的哪一部分说这是有效的?没有发现任何相关内容。

run()

2 个答案:

答案 0 :(得分:2)

但是run()函数中两个对象的地址“ a”和“ b”相同。

在传递左值时,Tdeduced作为左值引用,即int&。 (int& && collapsesint&,因此功能参数a的类型为int&。)然后将b声明为对a

传递右值时,T推导为int。 (因此,函数参数a的类型为int&&。)然后将b声明为从a复制的自变量。

答案 1 :(得分:1)

run(value)中,value是一个左值,它必须与T&&匹配。左值不能绑定到右值引用,因此T = intT = int&&不会这样做。唯一有效的是T&& = int&&。由于引用折叠,因此对左值引用的右值引用就是左值引用,因此T = int&的实例化如下:

run

很明显,断言总是会通过。现在,对于template<> void run<int&>(int &a) { int &b{a}; // expanding std::forward ++b; assert(b == a); assert(&b == &a); } ,该参数确实是一个右值,您得到run(std::move(value))。然后

T = int

这当然会失败。也许您应该替换

template<>
void run<int>(int &&a) {
    int b{std::move(a)};
    ++b;
    assert(b == a);
    assert(&b == &a);
}

使用

T b{std::forward<T>(a)};

这将从std::decay_t<T> b{std::forward<T>(a)}; 中删除引用(确保T是一个新的(已复制/​​移动的)对象),并且还将处理数组和函数(通过使b成为指针,即使{{ 1}}不是)。

您是否需要它们,但是[temp.deduct.call]/3讨论了转发引用的模板推导,[dcl.init.list]/3.9说,列表初始化引用只是将其绑定到初始化列表的元素。 [forward]也很好地解释了b。基本上,如果a是左值引用,则std::forward<T>是左值,否则是xvalue(一种rvalue)。 (基本上是有条件的T。)

相关问题