std::move、std::forward、值类型和模板推导 (注:这是一个提问标题,无需回答)

3

假设我有这段代码

template <typename T> void Swap(T&& a, T&& b) {
    T tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

int main()
{
    int a = 2;
    int b = 3;
}

根据我对这个讲座的理解,在调用Swap(a, b)时,编译器应该推断出T&&应该是T&并进行转换。但在这种情况下,GCC会给我以下错误:

error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'std::remove_reference<int&>::type {aka int}' 
T tmp = std::move(a);

我要么使用Swap(std::forward<int>(a), std::forward<int>(b))或者Swap(std::move(a), std::move(b))来调用Swap,要么将Swap的签名替换为Swap(T& a, T& b)。为什么会这样?这里应该如何正确使用?

2
编译器应该推断出 T&& 应该是 T&,所以第一行应该是 T& tmp = std::move(a);。这是无意义的,因为你不能将一个右值绑定到非 const 的左值引用上。你似乎知道这一点,所以我不明白你实际的问题是什么... - ildjarn
1
交换两个rvalue可能有点傻:Swap(1 + 2, 2 + 1)...?像std::exchange这样的东西可能会更有价值一些。 - Kerrek SB
根据我的经验,人们有时会在思考中遇到“盲区”。就像视野中间的盲区一样,除非你强迫你的视觉系统生成一个浮动的香肠(当教孩子如何做时,有些孩子会感到高兴),否则你根本不会注意到它。我最常见的盲区是二进制开关。也许这是支持宗教信仰的相同机制。无论如何,这很普遍。 - Cheers and hth. - Alf
@ildjarn 我在想编译器会将对 Swap(int&, int&) 的调用替换为 Swap(int& &&, int& &&),从而导致 T == int,而不是 T 然后导致 T 成为 int&。在这种情况下,错误是完全合理的。 - cmourglia
@KerrekSB 这只是我尝试时想到的第一个例子。 - cmourglia
1个回答

6
你需要这个:
template <typename T> void Swap(T&& a, T&& b)
{
    using U = typename std::remove_reference<T>::type;

    U tmp = std::move(a);
    a = std::move(b);
    b = std::move(tmp);
}

正如您在问题中暗示的, 在您的示例中,T被推断为int&,并且初始化 int& tmp = std::move(a); 是不合法的。


2
赶我一步了.. :( - Hatted Rooster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接