簡體   English   中英

調用專門的std :: move()

[英]Invoking specialized std::move()

我對以下示例中如何進行模板自變量推導感到困惑。 在本文的其余部分中,我將使用術語“ 調用 ”來表示實例化和invoke

我為我的自定義類型my_type專門化了std::move() ,並觀察到對於my_type類型的實例x

  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;
}

輸出:

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

當您調用std::move(a)a的類型為my_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);
}

然后將適當地調用它(但通用的將被要求std::move(static_cast<my_type&&>(a));

發生這種情況是因為通用定義如下所示:

template< class T >
constexpr typename std::remove_reference<T>::type&& move( T&& t );

T&&是關鍵。 在類型推導的上下文中,它可以綁定到my_type&my_type&&或任何cv( constvolatile )變體。 這就是為什么在沒有專業化的情況下它能夠為兩個調用調用通用版本的原因。

因此,要真正覆蓋所有基礎,您將需要多個重載。 不過,也許,為您的類型設置一個custom_move會更好。

因此,您的第一個問題是std中任何事物的專業化都必須遵守您正在專門化的事物的要求。 這意味着...您不得做任何其他事情。

其次, std::move的通用版本使用完美的轉發。 專業不能。

#define SPEC_MOVE(X) \
template<> inline \
typename std::remove_reference<X>::type&& move<X>(X t) noexcept \
{ \
  std::cout << "Invoke std::move() specialization\n"; \
  return static_cast<typename remove_reference<X>::type&&>(t); \
}
SPEC_MOVE(my_type&&)
SPEC_MOVE(my_type&)
SPEC_MOVE(my_type const&)
SPEC_MOVE(my_type const&&)
SPEC_MOVE(my_type const volatile&&)
SPEC_MOVE(my_type const volatile&)
SPEC_MOVE(my_type volatile&)
SPEC_MOVE(my_type volatile&&)

那應該做。

這是一個壞計划。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM