std :: remove_reference解释了什么?

时间:2013-06-08 13:52:46

标签: c++ templates c++11 template-specialization

我看到了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;};   

为什么lvaluervalue reference有专精?一般模板本身是否足够并删除引用?我在这里感到困惑,因为在T&T&&专业化中,如果我尝试使用::type,我仍然应该分别获得T&T&&吗?

你能解释为什么我们在移动中向remove_reference<t>::type&&施放? (是因为参数被命名所以它将被视为移动函数中的左值?)。

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

感谢您的时间。

2 个答案:

答案 0 :(得分:37)

  

为什么lvalue和rvalue引用有专门化?

如果只存在主模板,则执行:

remove_reference<int&>::type

会给你:

int&

并且正在做:

remove_reference<int&&>::type

会给你:

int&&

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

例如,如果你这样做:

remove_reference<int&&>

类型int&&将与T&&专精所指定的模式匹配,Tint。由于专门化将类型别名type定义为T(在本例中为int),执行:

remove_reference<int&&>::type

会给你int

  

你能解释为什么我们在remove_reference<t>::type&&转换为move

那是因为如果move()定义如下:

    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()的目的是给你一个右值,无论你输入什么。由于对返回类型为右值引用的函数的函数调用是rvalue,我们真的希望move()始终返回右值引用。

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

  

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

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

另一方面,如果你的目标是确保传递rvalue,你可以使用如下的静态断言:

#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&&)
{
    // ...
}

答案 1 :(得分:0)

当您将某个类型视为模板参数时,编译器会搜索最“专业”的特化。如果你传递int&amp;&amp;对于此模板,编译器使用remove_reference<T&&>版本。一般专业化不能满足您的需求 - 如果您将int&&传递给一般专业,则输入int&&

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