为什么在 std::move 中使用 std::remove_reference?

Why is std::remove_reference used in std::move?

我尝试实现 std::move,它使用 std::remove_reference,但没有它似乎也能正常工作。请给我一个实施失败的例子,其中 std::remove_reference 是必需的。

template <class type> type && move(type & source) { return (type &&) source; }
template <class type> type && move(type && source) { return (type &&) source; }

std::remove_reference是否只是为了避免重载std::move

这里有一个测试 class 可以帮助你:

class test {
public :
    test() { }
    test(const test & source) { std::cout << "copy.\n"; }
    test(test && source) { std::cout << "move.\n"; }
};

不是 How does std::move() transfer values into RValues? 的副本,因为我的问题包含一个示例,该示例似乎表明 std::remove_reference 在这种情况下 + 子问题是无用的。

该实现似乎有效,但两个函数声明重叠。

 template <class type> type && move(type && source) { return (type &&) source; }

此处 type && source 被解释为通用引用而不是 r-value 引用。因此,它可以接受任何输入,包括 l-value 参考,对于 l-value 参考输入,它将 return 一个 l-value 参考输出——这是一个潜在的问题。

最好避免多个模板函数声明可以接受相同输入的情况,因为这会导致各种问题。虽然,也许有一个 C++ 标准规则在处理通用引用时强制调用某些模板函数声明而不是另一个。您需要向语言律师询问该信息。

您可以使用 std::remove_reference 通过单个模板函数声明实现移动,如下所示:

  template <class type>
  std::remove_reference_t<type> && move(type && source) 
  { 
      return (std::remove_reference_t<type>&&) source; 
  }

一般来说,std::remove_reference 在处理通用引用时有助于确定输入的是哪种类型,并从中获取更多信息(尽管通常使用 std::remove_cv_ref_t 或等价物)。

I tried implementing std::move, which uses std::remove_reference, however it seems to work without it.

是的,它正在工作,因为您明确地为左值引用提供了重载。而 std::remove_reference 仅在您使用转发引用时才相关。

如果你去掉这一行: Godbolt

template <class type> type && move(type & source) { return (type &&) source; }

并将您的函数命名为:

test t2 = move(t1); //prints copy

要完成这项工作,您必须使用 std::remove_referenceTry on Godbolt:

template <class type>
std::remove_reference_t<type> && move(type && source)
{
    return
    static_cast<std::remove_reference_t<type>&& >(source);
}