调用专门的std :: move()

Sou*_*Roy 2 c++ stl template-specialization move-semantics c++11

我对如何在下面的例子中进行模板参数推断感到困惑.我在本文的其余部分使用术语invoke来暗示实例化和调用.

我专注std::move()于我的自定义类型my_type,我观察到,对于x类型的实例my_type:

  1. std::move(x) 继续调用通用模板
  2. std::move(static_cast<my_type&&>(x))std::move(std::forward(x))调用专业化
  3. 在没有我的专业化的情况下,所有上述调用都会调用通用模板

我的问题是:

  • 为什么上面第1项中的调用没有调用专门化?
  • 在没有专业化的情况下,#1和#2项中的调用如何表现相同?

这是整个代码:

#include<iostream>
#include<utility>

struct my_type
{
    int x;
};

namespace std
{

// This is the std::move() definition in the preprocessor output:
//
// template <class _Tp>
// inline __attribute__ ((__visibility__("hidden"), __always_inline__)) constexpr
// typename remove_reference<_Tp>::type&&
// move(_Tp&& __t) noexcept
// {
//     typedef typename remove_reference<_Tp>::type _Up;
//     return static_cast<_Up&&>(__t);
// }

// This is std::move() specialized for my_type
template<>
inline
typename std::remove_reference<my_type>::type&&
move<my_type>(my_type&& t) noexcept
{
    std::cout << "Invoke std::move() specialization\n";
    return static_cast<typename remove_reference<my_type>::type&&>(t);
}

} // namespace std

int main()
{
  auto a = my_type();

  std::cout << "Execute 'auto b = std::move(a);'\n";
  auto b = std::move(a); // Invokes the generic template

  std::cout << "Execute 'auto c = std::move(static_cast<my_type&&>(a));'\n";
  auto c = std::move(static_cast<my_type&&>(a)); // Invokes the specialization

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Execute 'auto b = std::move(a);'
Execute 'auto c = std::move(static_cast<my_type&&>(a));'
Invoke std::move() specialization
Run Code Online (Sandbox Code Playgroud)

And*_*dyG 5

当你调用is std::move(a)的类型时,不是.因此,泛型是更好的匹配,因为它可以完全匹配.amy_type&my_type&&std::move

如果您将重载更改move为如下所示:

inline
typename std::remove_reference<my_type>::type&&
move(my_type& t) noexcept
{
    std::cout << "Invoke std::move() specialization\n";
    return static_cast<typename remove_reference<my_type>::type&&>(t);
}
Run Code Online (Sandbox Code Playgroud)

然后它将被适当地调用(但通用的将被调用std::move(static_cast<my_type&&>(a));)

发生这种情况是因为通用定义如下所示:

template< class T >
constexpr typename std::remove_reference<T>::type&& move( T&& t );
Run Code Online (Sandbox Code Playgroud)

T&&是关键.在型扣的上下文中其可以结合到二者my_type&,my_type&&或任何CV(constvolatile)的变化.这就是为什么在没有专业化的情况下,它能够为两个调用调用通用版本.

因此,要真正覆盖所有基础,您将需要多个重载.但是,你可能会custom_move因为你的类型受到限制而变得更好.