标准也称为成员函数的引用限定符的“*this的右值引用”最典型的用例是什么?
顺便说一句,关于这个语言特性here有一个很好的解释。
发布于 2013-07-08 18:21:01
调用时,每个成员函数都有一个*this引用的隐式对象参数。
所以(a)这些正常的函数重载:
void f(const T&);
void f(T&&);当像f(x)一样调用时;以及(b)这些成员函数重载:
struct C
{
void f() const &;
void f() &&;
};当像x.f()一样调用时- (a)和(b)调度都具有类似的可行性和排名。
因此,用例基本上是相同的。它们是为了支持移动语义优化。在rvalue成员函数中,您实际上可以掠夺对象资源,因为您知道它是一个即将过期的对象(即将被删除):
int main()
{
C c;
c.f(); // lvalue, so calls lvalue-reference member f
C().f(); // temporary is prvalue, so called rvalue-reference member f
move(c).f(); // move changes c to xvalue, so again calls rvalue-reference member f
}举个例子:
struct C
{
C operator+(const C& that) const &
{
C c(*this); // take a copy of this
c += that;
return c;
}
C operator+(const C& that) &&
{
(*this) += that;
return move(*this); // moving this is ok here
}
}发布于 2013-07-08 19:39:35
某些操作在调用rvalue时效率更高,因此*this的value类别上的重载允许自动使用最有效的实现,例如
struct Buffer
{
std::string m_data;
public:
std::string str() const& { return m_data; } // copies data
std::string str()&& { return std::move(m_data); } // moves data
};(这种优化可以针对std::ostringstream完成,但还没有正式提出。)
有些操作调用rvalue没有意义,因此在*this上重载允许删除rvalue表单:
struct Foo
{
void mutate()&;
void mutate()&& = delete;
};我实际上还不需要使用这个特性,但是现在我关心的两个编译器支持它,也许我会发现它有更多的用途。
发布于 2013-07-08 21:28:01
在我的编译器框架(不久将发布™)中,将令牌等信息项传递到编译器对象中,然后调用finalize来指示流的结束。
在不调用finalize的情况下销毁一个对象是不好的,因为它不会刷新所有的输出。然而,析构函数不能完成finalize,因为它可能抛出异常,同样,如果解析器已经中止,那么要求finalize提供更多输出也是错误的。
在所有输入都已经被另一个对象封装的情况下,将输入传递给rvalue编译器对象是很好的。
pile< lexer, parser >( output_handler ).pass( open_file( "source.q" ) );如果没有特殊的支持,这一定是不正确的,因为finalize不会被调用。界面根本不应该让用户做这样的事情。
首先要做的是排除finalize永远不会被调用的情况。如果使用左值引用限定符调整原型,则上面的示例是不允许的:
void pass( input_file f ) & {
process_the_file();
}这为添加另一个重载提供了空间,该重载可以正确地完成对象。它是右值ref限定的,因此只有在即将到期的对象上调用时才会选择它。
void pass( input_file f ) && {
pass( std::move( f ) ); // dispatch to lvalue case
finalize();
}现在,用户几乎不需要担心要记住调用finalize,因为大多数编译器对象最终都被实例化为临时对象。
注意,这类事情并不是ref限定的成员所特有的。对于t &和t &&,任何函数都可以有单独的重载。pass目前的实际实现方式是使用完美的转发,然后回溯来确定正确的语义:
template< typename compiler, typename arg >
void pass( compiler && c, arg a ) {
c.take_input( a );
if ( ! std::is_reference< compiler >::value ) {
c.finalize();
}
}有许多方法可以处理重载。实际上,非限定成员函数通常不关心被调用的对象的类别(左值或右值),也不会将该信息传递给函数。除了隐式this之外,任何函数参数都必须说明其参数的类别。
https://stackoverflow.com/questions/17521238
复制相似问题