【问题标题】:Difference between add_lvalue_reference_t<T> and T&add_lvalue_reference_t<T> 和 T& 之间的区别
【发布时间】:2015-11-15 19:24:19
【问题描述】:

假设您有一个模板参数T

两者有什么区别

  • add_cv_t&lt;T&gt;const volatile T
  • add_const_t&lt;T&gt;const T
  • add_volatile_t&lt;T&gt;volatile T
  • add_lvalue_reference_t&lt;T&gt;T&amp;
  • add_rvalue_reference_t&lt;T&gt;T&amp;&amp;
  • add_pointer_t&lt;T&gt;T*?

例如,为什么我应该使用add_rvalue_reference_t&lt;T&gt; 而不是T&amp;&amp;。什么时候选哪个有什么规定吗?

【问题讨论】:

    标签: c++ templates c++11 generic-programming


    【解决方案1】:
    • add_cv_t&lt;T&gt;const volatile T
    • add_const_t&lt;T&gt;const T
    • add_volatile_t&lt;T&gt;volatile T

    没有区别;例如add_const&lt;T&gt;::type 的定义就是T const

    • add_lvalue_reference_t&lt;T&gt;T&amp;
    • add_rvalue_reference_t&lt;T&gt;T&amp;&amp;

    T&amp;T&amp;&amp;Tcv void 时格式不正确,但这些模板格式正确,只是返回原始类型。

    • add_pointer_t&lt;T&gt;T*?

    add_pointer_t&lt;T&gt; 等价于std::remove_reference&lt;T&gt;::type*。也就是说,如果T 是一个引用类型,它会给出一个指向被引用类型的指针。另一方面,T* 格式错误,因为您不能拥有指向引用的指针。

    你应该使用哪个?

    • 一般情况下,可以使用别名模板来防止T的扣除。当然,这意味着如果你想扣除,你应该避免它们。
    • 别名模板可用作将类型转换作为参数的模板的模板模板参数。
    • 在行为上与T* 等替代模板不同的别名模板在通用代码中很有用,因为它们“做正确的事”。例如,如果T 是从T&amp;&amp; 类型的参数推导出来的,那么当参数是左值时T* 会做错事,因为它试图声明指向左值引用的指针。但是std::add_pointer_t&lt;T&gt; 会给出一个指向参数实际类型的指针。

    【讨论】:

      【解决方案2】:

      根据我在 STL 源码中看到的:

      add_cv_t&lt;T&gt;const volatile T- 没有区别

      add_const_t&lt;T&gt;const T - 没有区别

      add_volatile_t&lt;T&gt;volatile T - 没有区别

      add_lvalue_reference_t&lt;T&gt;T&amp; - 例如,如果 T 是不可引用类型 void,则存在差异。 add_lvalue_reference_t&lt;void&gt;::type = voidvoid&amp; = 编译时错误

      add_rvalue_reference_t&lt;T&gt;T&amp;&amp; - 同上

      add_pointer_t&lt;T&gt;T* - T 是引用时的区别,因为没有指向引用的指针。 add_pointer_t&lt;T&gt; 等价于std::remove_reference&lt;T&gt;::type*

      【讨论】:

      • 有趣,为什么要否决这个答案?
      • 编译时错误不确定。在某些实现中不会发生错误
      【解决方案3】:

      在大多数情况下,std::add_rvalue_reference_t&lt;T&gt; 等同于 T&amp;&amp;。但是,reference collapsing rules 和 the-rules-that-dictate-which-types-are-referenceable 如果不加以考虑,可能会使您的代码行为不端。

      但是,由于T 是不可引用的类型,在某些情况下type 静态成员类型会有所不同。例如std::add_rvalue_reference_t&lt;void&gt;解析为void,并且(以你提到的另一个模板为例)std::add_pointer_t&lt;T&amp;&gt;解析为T*(如果你想调用混乱,所需的仪式是std::add_pointer_t&lt;std::add_rvalue_reference_t&lt;void&gt;&gt;:))

      就用途而言,它可以作为模板模板参数来做一些时髦的黑魔法。无论如何,std::is_rvalue_reference_t&lt;T&gt;std::remove_reference_t&lt;T&gt; 之类的东西通常在操作类型的引用属性时更常用。

      【讨论】:

      • 最好说“可能”而不是断言可能(不知何故)不是这样的事情。这背后的要点和“他/她的意见”是 OP 没有具体说明他/她在做什么(或者更确切地说,为什么)。是简单的理论吗?或者更确切地说,正如我所说的,“黑魔法”?我们不知道,参考折叠规则会在很大程度上影响他/她的代码是否行为不端(如果不考虑的话)。
      • 顺便说一句,我再次编辑。在之前的编辑中,第一段变得毫无意义,所以@Barry 有他的观点。
      • 别名模板如何影响参考折叠?
      • 您可能的意思是“引用折叠如何影响别名模板?”,它本身应该改写为“引用折叠如何影响模板?”。嗯,答案有点复杂,应该在另一个问题上解决。
      猜你喜欢
      • 1970-01-01
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-07
      • 2021-04-09
      • 2016-01-19
      相关资源
      最近更新 更多