右值模板参数隐式用作左值,并且 std::转发工作
rvalue template argument implicitly used as lvalue, and std::forwarding working
这个关于std::forward
用法的例子让我感到困惑。这是我编辑的版本:
#include <iostream>
#include <memory>
#include <utility>
using namespace std;
struct A{
A(int&& n) { cout << "rvalue overload, n=" << n << "n"; }
A(int& n) { cout << "lvalue overload, n=" << n << "n"; }
};
template<typename> void template_type_dumper();
template<class T, class U>
unique_ptr<T> make_unique(U&& u){
//Have a "fingerprint" of what function is being called
static int dummyvar;
cout<<"address of make_unique::dummyvar: "<<&dummyvar<<endl;
//g++ dumps two warnings here, which reveal what exact type is passed as template parameter
template_type_dumper<decltype(u)>;
template_type_dumper<U>;
return unique_ptr<T>(new T(forward<U>(u)));
}
int main()
{
unique_ptr<A> p1 = make_unique<A>(2); // rvalue
int i = 1;
unique_ptr<A> p2 = make_unique<A>(i); // lvalue
}
输出为
address of make_unique::dummyvar: 0x6021a4
rvalue overload, n=2
address of make_unique::dummyvar: 0x6021a8
lvalue overload, n=1
关于引用template_type_dumper
的警告表明,在第一个实例中,decltype(u) = int&&
和U = int
,对于第二个decltype(u) = int&
和U = int&
。
预期的那样有两个不同的实例,但她是我的问题:
std::forward
如何在这里工作?在第一个实例化中,它的模板参数是显式U = int
的,它怎么知道它必须返回一个右值引用?如果我改为指定U&&
会发生什么?-
make_unique
声明为采用右值引用。为什么u
可以成为左值参考?我缺少什么特殊规则吗?
make_unique
被声明为采用右值引用。你怎么能成为左值参考?我缺少什么特殊规则吗?
make_unique
声明为参考。这种参照是什么样的,有待推论。如果传递了类型 foo
的左值,则U
被推导为foo&
并且由于引用折叠规则U&&
变得foo&
(基本上,将一个右值引用与另一个引用"组合"总是产生一个右值引用;合并两个右值引用会产生一个右值引用(。如果传递 foo
类型的右值,则U
被推导为 foo
并且U&&
foo&&
。
这是支持完美转发的原因之一:使用U&&
,您可以同时采用左值和右值,并推断出U
以匹配适当的值类别。然后,使用 std::forward
您可以转发保留相同值类别的值:在第一种情况下,您得到转发左值的std::forward<foo&>
,在第二种情况下,您将获得转发右值std::forward<foo>
。
在第一个实例化中,它的模板参数显式为 U = int,它怎么知道它必须返回一个 rvalue-reference?
因为std::forward<T>
的返回类型始终是T&&
。如果传递int
则返回int&&
。如果传递int&
则由于引用折叠规则,它将再次返回int&
。
如果我指定 U&& 会发生什么?
你会有std::forward<int&&>
,引用折叠规则使int&& &&
仍然是一个右值引用:int&&
.
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- 为什么可以将 std::unique_ptr* u1 <A>作为 u1[1000] 访问并且它仍然有效
- CLion 无法解析类型 std::unordered_map,即使它提示我包含标头并且编译工作
- 为什么 std::make_unique<std::thread>(somefun()) 会在我没有调用 release() 时生成崩溃,并且在调用时会生成崩溃?
- 来自类型为std::basic_string::const_iterator的非常量引用的无效初始化,并且<char>来自类型std::basic_string<char>::
- std::vector::reserve(未知m),我知道m<<;N(通常)并且知道N
- 类型为'std::string&的非常量引用的初始化无效,并且从类型为'std::basic_string<char>的右值
- 我们应该序列化 std::chrono::d uration 类还是 P.O.D.(普通旧数据)并且不需要序列化
- 为什么在 std::transform 中使用函数对象参数失败并且需要 lambda 表达式
- C 类变量STD ::功能具有默认功能,并且可以更改
- 为什么 std::copy 抛出错误向量迭代器 + 偏移量超出范围并且无法复制
- 右值模板参数隐式用作左值,并且 std::转发工作
- 我想返回一个向量函数,<Competition>但被告知竞争是未声明的,并且我正在使用未定义的类'std::vector'
- 从std::列表中删除项,并且只能访问迭代器
- 无论模板参数如何,哪些std::map方法是相同的(并且可能共享符号)
- 为什么 <conio.h> 有时不起作用,并且在 C++ 中使用命名空间 std 可以工作