考虑以下代码:
template<typename T>
T mov(T&& t){
return std::move(t);
}
int main(){
std::unique_ptr<int> a = std::unique_ptr<int>(new int());
std::unique_ptr<int> b = mov(a);
}
mov
函数应该只是采用通用引用并按值返回,但是move
而不是复制。因此,调用此方法时不应涉及复制。因此,使用只能移动的unique_ptr
来调用这样的函数应该没问题。但是,此代码无法编译:我收到错误:
test.cpp:24:34: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
std::unique_ptr<int> b = mov(a);
所以C ++似乎试图调用unique_ptr
的拷贝构造函数,这当然是删除的。但为什么副本会在这里发生?我怎样才能编译这段代码?
答案 0 :(得分:3)
我终于找到了一个有效的解决方案。我认为问题是按值返回会触发副本。相反,我需要通过右值参考返回;然后将自动进行移动。首先我尝试了这个:
template<typename T>
T&& mov(T&& t){
return std::move(t);
}
但现在问题是返回类型T&&
是通用引用,而不是右值引用。因此,当使用左值调用函数时,实际签名为T& mov(T& t)
。因此,它的主体将无法编译,因为我无法std::move
到左值引用。这正是发生的事情,这是错误:
test.cpp:18:22: error: invalid initialization of non-const reference of type
‘std::unique_ptr<int>&’ from an rvalue of type ‘std::remove_reference<std::unique_ptr<int>&>::type {aka std::unique_ptr<int>}’
return std::move(t);
所以,我需要一个真正的右值引用作为返回类型。起初,我不知道如何构建它,但最后,我发现我首先需要std::remove_reference
类型T
,然后添加&&
,然后我会有一个实际右值参考T&&
。并且它有效,这个版本的mov
编译得很好并解决了问题:
template<typename T>
typename std::remove_reference<T>::type&& mov(T&& t){
return std::move(t);
}
正如Niall所说,通过引用返回也可以使用remove_reference
而不使用&&
:
template<typename T>
typename std::remove_reference<T>::type mov(T&& t){
return std::move(t);
}
答案 1 :(得分:3)
我认为错误是在mov
代码应该是
#include <utility>
#include <memory>
template<typename T>
typename std::remove_reference<T>::type&& mov(T&& t){
return std::move(t);
}
int main(){
std::unique_ptr<int> a = std::unique_ptr<int>(new int());
auto b = mov(a);
}
这个问题暗示了按价值回归的情况,这也是一个问题。我不确定它是否适用于您的情况;
template<typename T>
typename std::remove_reference<T>::type mov(T&& t){
return std::move(t);
}