在下面的示例中,我对模板参数推断是如何发生的感到困惑。在本文的其余部分中,我使用了术语invoke来暗示实例化和调用。
我为我的自定义类型std::move()专门化了my_type,并且我观察到,对于my_type类型的x,
std::move(x)继续调用泛型模板std::move(static_cast<my_type&&>(x))或std::move(std::forward(x))调用专门化我的问题是:
以下是整个代码:
#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发布于 2017-05-10 22:43:48
当您调用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 (const或volatile)变体。这就是为什么在没有专门化的情况下,它能够为两个调用调用通用版本。
因此,要真正覆盖所有的基地,你需要一个以上的过载。尽管如此,您最好还是使用custom_move来限制您的类型。
发布于 2017-05-10 23:27:56
因此,您的第一个问题是,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&&)这样就行了。
这是个糟糕的计划。
https://stackoverflow.com/questions/43903698
复制相似问题