49

我看到了可能的实现std::remove_reference如下

template< class T > struct remove_reference      {typedef T type;};
template< class T > struct remove_reference<T&>  {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};   

为什么有 和 的lvalue专业化rvalue reference?通用模板本身是否足够并删除参考?我在这里感到困惑,因为在T&orT&&专业化中,如果我尝试使用::type我仍然应该得到T&orT&&对吗?

你能解释一下,为什么我们remove_reference<t>::type&&在 move 中施法吗?(是不是因为参数被命名所以它会被视为移动函数内的左值?)。

另外,您能否指出一种方法,使我可以找出并打印类型是什么?例如,如果它是一种rvalue类型,int那么我应该能够打印出int&&通过的?(我一直在使用std::is_same手动检查。)

感谢您的时间。

4

2 回答 2

50

为什么有左值和右值引用的专业化?

如果仅存在主模板,则执行以下操作:

remove_reference<int&>::type

会给你:

int&

并做:

remove_reference<int&&>::type

会给你:

int&&

这不是你想要的。左值引用和右值引用的特化允许分别从您传递的类型参数中剥离&和。&&

例如,如果您正在执行以下操作:

remove_reference<int&&>

类型int&&将与特化指定的模式匹配T&&Tint。由于特化将类型别名定义typeT(在本例中为int),因此:

remove_reference<int&&>::type

会给你int

你能解释一下我们为什么要投remove_reference<t>::type&&进去move吗?

这是因为 ifmove()定义如下:

    template<typename T>
    T&& move(T&& t) { ... }
//  ^^^
//  Resolves to X& if T is X& (which is the case if the input has type X
//  and is an lvalue)

然后返回类型将是X&如果参数move()是类型的左值X(这就是所谓的“通用引用”)。我们要确保返回类型始终是右值引用。

的目的move()是为您返回一个右值,无论您输入什么。由于对返回类型为右值引用的函数的函数调用是右值,所以我们真的希望move()总是返回一个右值引用。

这就是我们这样做的原因remove_reference<T>::type&&,因为附加&&到非引用类型总是保证产生右值引用类型。

您还可以指出一种方法,让我可以找出并打印类型是什么?

我不确定您在这里所说的“打印”是什么意思。我知道没有可移植的方式将类型的名称转换为字符串(无论您如何获得该类型)。

另一方面,如果您的目标是确保传递了一个右值,则可以使用如下静态断言:

#include <type_traits>

template<typename T>
void foo(T&&)
{
    static_assert(!std::is_reference<T>::value, "Error: lvalue was passed!");
    // ...
}

这依赖于这样一个事实,即当X传递类型的左值时,T将推断为X&.

如果您只想产生替换失败,您也可以使用等效的 SFINAE 约束:

#include <type_traits>

template<typename T, typename std::enable_if<
    !std::is_reference<T>::value>::type* = nullptr>
void foo(T&&)
{
    // ...
}
于 2013-06-08T13:58:59.273 回答
0

当您将某些类型视为模板参数时,编译器会搜索最“专业化”的专业化。如果您将 int&& 传递给此模板,则编译器使用remove_reference<T&&>版本。一般专业不会给你你想要的 - 如果你通过int&&一般专业,类型将是int&&

如果要打印类型,请使用typeid(some_type).name()

于 2013-06-08T14:01:18.787 回答