【问题标题】:Need an example of reference collapsing rule T&&&& -> T&& on VS2017需要一个参考折叠规则的例子 T&&&& -> T&& on VS2017
【发布时间】:2021-01-20 07:43:24
【问题描述】:

给定 C++ 参考折叠规则的几个来源如下:

A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&

(例如http://thbecker.net/articles/rvalue_references/section_08.html

我可以举一个例子让A&&&变成A&

template <class T> void f1(T&& param) {
    // T t = 5;  // does not compile because T is T&
    param++; // param collapses from int&&&& to int&&
}

void demo()
{
    int x = 8;
    int &y = x;
    f1(y);   // OK T will still be int&, param will go to int&&& -> collapses to int&
    cout << y;  // prints 9
}

我希望 A&& && 变成 A&& 的类似内容,但是当我使用 RValue 调用时,T 被推导出为 int,因此这并没有显示我想要的结果。

template <class T> void f1(T&& param) {
    T t = 5;  // compiles since T is int
    T t2 = t; // would not compile if T was int&&
    t2++;
    cout << t; // prints 5 since t2 was not a reference
}

void demo()
{
    f1(8);   // OK T deduced to int, param will go to int&& , no collapsing
}

谁能帮我展示一个类似的例子,将 T 推导出为 T&& 并将参​​数从 T&&&& 折叠为 T&&?

【问题讨论】:

  • 你可以叫它f1&lt;int&amp;&amp;&gt;(8);
  • 我尝试使用 clanggcc,这会产生您预期的编译器错误,即 T t2 = t; 无法编译。
  • 考虑,例如,f1&lt;decltype( xvalue )&gt;(...));。这里,T 将是 some_type&amp;&amp;param 的类型将从 some_type&amp;&amp; &amp;&amp; 折叠到 some_type&amp;&amp;

标签: c++ templates forwarding-reference


【解决方案1】:

谁能帮我展示一个类似的例子,将 T 推导出为 T&& 并将参​​数从 T&&&& 折叠为 T&&?

如果我们谈论的是实际的演绎,其中模板参数T 没有明确给出或以某种方式默认,这是不可能的。原因是转发不仅仅依赖于引用折叠。

首先,我们必须注意,在 C++ 中,函数(模板)的参数始终是某种表达式。并且表达式永远没有引用类型。

[expr.type]

1 如果一个表达式最初的类型是“对 T 的引用” ([dcl.ref], [dcl.init.ref]),类型调整为 T 之前的任何 进一步的分析。表达式指定对象或功能 由引用表示,并且表达式是左值或 xvalue,取决于表达式。

您实际上不能为引用类型的函数生成参数。所以T在正常情况下不能被推断为一个引用。转发也依赖于模板中引用函数参数的特殊情况。

[temp.deduct.call]

3如果P是引用类型,则P所引用的类型用于 类型扣除。 [...] 转发引用是一个右值引用 不代表模板的 cv 非限定模板参数 类模板的参数(在类模板参数期间 扣除([over.match.class.deduct]))。如果 P 是转发参考 并且参数是一个左值,“对 A 的左值引用”类型是 用于代替 A 进行类型推导。

如您所见,转发引用是专门围绕作为参数提供的表达式的值类别设计的。只有当表达式是左值时,参数的类型才会被视为“对 A 的左值引用”。否则,不进行任何调整。所以T 将被推断为被引用的类型

引用折叠规则仅在明确给出类型参数时才起作用。在这种情况下,当int&amp;&amp; 以某种方式提供时,我们会通过引用折叠获得一个右值引用。但不是在模板参数推演之后。

【讨论】:

  • 感谢您的详细回复。这里有很多事情要做。首先,我喜欢通过使用类型显式实例化模板来显示示例的想法。我一定会使用它。至于不能为引用类型的函数生成参数,在我看来,在某些情况下您可以。例如,当我的第一个示例中的参数是 int& 并且参数是 T&& 时,T 变为 int&,如我的第一个示例所示。如果我错了,请纠正我。
  • @GonenI - 参数永远不是int&amp;。当您通过y 时,它是int 类型的id 表达式(如第一段所述)。它也是一个左值,这就是为什么转发引用的模板参数推导调整类型为int&amp;。但它与y 本身(作为表达式)属于int&amp; 类型不同。这就是这里的关键。当参数不是左值时,没有调整。所以我们只剩下值类型了。
【解决方案2】:

在评论者和其他回答者的帮助下,我想出了这个演示:

template <class T> void f1() {
    int x = 5; // an lvalue
    //T t1 = x; // compiles when T is int or int&, fails when T is int&
    //T& t2 = x; // always compiles, becomes int&. Can check with ++t2; cout << x;
    //T&& t3 = x; // compiles when T is int&, fails when t3 is &&
}

void demo()
{
    //f1<int>();     // T becomes int, t1=int,  t2=int&   t3=int&&
    //f1<int&>(); // T becomes int&  t1=int& t2=int& t3=int&
    f1<int&&>(); // T becomes int&&, t1=int&&  t2=int&, t3=int&&
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-11
    相关资源
    最近更新 更多