【问题标题】:Forwarding references: reference parameter origin转发引用:引用参数origin
【发布时间】:2022-01-23 10:54:24
【问题描述】:

关于转发引用(又名通用引用)的全部前提是,这个函数:

template<typename T>
void f(T&&) { }

可以导致模板参数为int&amp;int,具体取决于您是否以int a{}; f(a)f(5) 为例。但这已经是我认为的一步太远了。因为当我有这样的功能时

template<typename T>
auto g(T) -> void {}

然后它总是将模板参数解析为int,不管我如何称呼它。尽管auto h(int&amp;) -&gt; void {} 是完全合法的。

那么,有哪些规则允许f 的模板参数作为参考,而不是g 的模板参数?

【问题讨论】:

  • 我假设您已经阅读了en.cppreference.com/w/cpp/language/reference 那么,还有什么不清楚的地方?我不是在讽刺。我发现很多关于这件事的文字我自己都不清楚,但为了写出一个好的答案,了解你在哪里遇到了困难。
  • 我会通读一遍,但我认为问题很清楚?为什么 f 的模板参数在使用左值调用时会解析为 T& 而 g 不是?
  • @Basti 因为它不能。 T 只是一个 typename。它不会自动包含&amp;。为此,您需要输入&amp;&amp;&amp;,如g(T&amp;)
  • 当使用 T&& 参数时,T 确实变成了 T& - 这就是重点

标签: c++ templates forwarding-reference


【解决方案1】:

对于函数参数的形式为T&amp;&amp;(cv-unqualified),其中T 是模板参数的情况,模板参数推导规则中有一个特定的例外。这种特殊情况在称为转发参考的问题中可以看到。

对于转发引用,如果函数参数是左值,则推导出 T 的左值引用,通常不会推导出引用类型。

您可以通过尝试使用例如const T&amp;&amp; 而不是 T&amp;&amp;,特殊规则不适用。在任何情况下,它都会为 T 推导出一个非引用类型,尽管函数调用可能是不可能的。

【讨论】:

    【解决方案2】:

    你可以阅读Effective modern C++的答案,第一章,它说,我们可以把函数模板想象成这样:

        template<typename T>
        void f(paramType param);
    

    TparamType 通常是不同的,paramType 通常包含诸如 const 之类的修饰符或诸如 const T&amp; 之类的引用限定符

    他在三个案例中谈到了这个

    1. paramType 是指针或引用类型
    2. paramType 是通用引用
    3. paramType 既不是指针也不是引用

    你的第一个函数是case2,因为需要推导类型,&amp;&amp;这里是通用引用,你的第二个函数是case3,paramType既不是指针也不是引用

    在类型推导期间,模板参数是通用的 同类型的reference、lvalues和rvalues被推论有 类型略有不同。

    • 类型 T 的左值被推断为类型 T&
    • 类型 T 的右值被推导出为类型 T

    所以f(a) 你得到了f(int&amp; &amp;&amp; param) 然后是“引用折叠”的规则

    • 对右值引用的右值引用变为右值引用
    • 对引用的所有其他引用都折叠为左值引用

    所以你得到了f(int&amp; param)

    【讨论】:

      猜你喜欢
      • 2017-10-01
      • 2020-03-07
      • 2018-02-10
      • 1970-01-01
      • 2013-05-08
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      • 2019-05-23
      相关资源
      最近更新 更多