【问题标题】:Forwarding references, ref qualifiers and template member functions转发引用、引用限定符和模板成员函数
【发布时间】:2016-08-30 15:54:10
【问题描述】:

取如下成员函数:

struct T {
    template <typename X> void f(X&& x) { /* ... */ }
};

在这种情况下,x 是一个转发引用,因为&amp;&amp; 用于模板内的函数参数。这符合预期。

现在使用这个函数:

struct T {
    template <typename X> void f(X&& x) && { /* ... */ }
};

我希望this 会以类似的方式处理;作为转发参考。因此,我希望以下程序能够正常编译和运行:

#include <iostream>

struct T {
    template <typename X>
    bool operator<(X&& rhs) && {
        std::cout << "&&" << std::endl;
        return true;
    }
};

int main() {
    T t;
    std::cout << (t < T()) << std::endl;
    return 0;
}

但是使用 GCC 4.8.4 和 6.0.1,它不会。相反,我得到以下信息:

rvalue.cpp: In function ‘int main()’:
rvalue.cpp:13:25: error: passing ‘T’ as ‘this’ argument of ‘bool T::operator<(X&&) && [with X = T]’ discards qualifiers [-fpermissive]
 std::cout << (t < T()) << std::endl;

this 似乎没有被作为转发引用。 这是正确的还是错误的? this 是否应该被视为转发参考?标准的哪一部分规定了这一点?

【问题讨论】:

  • @JoachimPileborg 刚刚使用 6.0.1 进行了尝试,结果相同。不过谢谢!

标签: c++ templates language-lawyer member-functions forwarding-reference


【解决方案1】:

这里的两个&amp;&amp;s`区别对待:

struct T {
    template <typename X> void f(X&& x) && { /* ... */ }
};

你是对的,x 是一个转发引用。但是右边的&amp;&amp; 是对对象实例的限定。在这种情况下,f() 只能在对象实例是右值的情况下被调用(也许更令人困惑的是,第一个 &amp;&amp;x 作为转发引用,而第二个 &amp;&amp; 采用隐式对象参数作为右值参考)。那就是:

T().f(4); // ok

T t;
t.f(4); // error

这与const 资格的工作方式相同:

struct X { void f(); };
const X cx;
cx.f(); // error

【讨论】:

  • 所以模板不会影响&amp;&amp;如何应用于this
  • @OMGtechy 这些是完全不同的概念。您不能对函数的限定进行模板化 - 如果您想要左值和右值重载,则需要分别具有 &amp;- 和 &amp;&amp;- 限定函数。
  • 谢谢。标准中是否有规定这种区别的地方?
  • @OMGtechy cv-qualifiers 和 ref-qualifiers 控制隐式 this 参数的类型 - 在 [over.match.funcs] 中详细说明。
【解决方案2】:

函数末尾的引用限定符声明 operator&lt; 仅应在 LHS 是临时的时调用。请记住,运算符可以像任何其他成员函数一样被调用,所以你所拥有的是

t.operator<(T())

t 不是临时的。

如果我们将您的示例更改为

std::cout << (T() < t) << std::endl;

然后它就可以正常工作了,因为您调用 operator&lt; 的对象是一个临时对象。

【讨论】:

  • 我明白这一点,我要问的是为什么 this 不像参数那样被转发引用。
  • @OMGtechy 因为编译器不仅仅是将您的对象转换为右值。如果是这样,那么参考资格将毫无用处。您说该函数只能在右值上调用。当你打破它并在一个左值对象上调用它时,你会得到一个编译器错误。
  • @OMGtechy:首先,forwarding-referencervalue-reference 是有区别的。其次,在成员函数内部,this既不是转发引用,也不是右值引用,即使在只能在右值上调用的函数中,其中case this,虽然本身仍然是一个左值,但绑定到 rvalue 表达式。
  • @OMGtechy:如果您知道,那么您一定知道术语 forwarding-reference 仅在 function template 参数的上下文中相关T&amp;&amp; 的形式。否则,它没有意义;它在其他任何地方都没有任何相关性,甚至在类模板参数中也没有。首先必须是函数模板,然后参数必须是T&amp;&amp;的形式。
  • auto&amp;&amp;,实际上只是T&amp;&amp;
【解决方案3】:

成员operator&lt;() &amp;&amp;只能在右值上调用,所以如下:

t < T()

不会起作用,因为t 不是右值——它是左值

以下应该有效:

std::move(t) < T()

还有这个:

T{} < T{}

请注意,我使用了 {},因为我对它们更满意,而且它们的工作方式并不令人惊讶。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 2020-01-17
    • 1970-01-01
    • 2020-02-15
    • 2011-05-05
    相关资源
    最近更新 更多