请注意,有关模板函数或成员函数的先前答案,但此问题仅与非模板非成员函数有关。 std :: move()返回T&&,但它是一个模板函数。
是否有充分的理由使用T&&作为非模板和非成员函数的返回类型,其中T是任意类型?
例如,您何时会使用以下内容?
T&& fn()
{
....
return ....
}
我已经看过使用过这个例子的例子,但是在所有的例子中,开发人员误解了移动语义,应该按价值返回并利用NRVO。
答案 0 :(得分:0)
假设我们有一个粒子系统。我们希望将其实现为粒子池。这意味着我们要反复回收相同的粒子,因此为了重用资源,我们希望传递rvalues。
现在,假设我们的粒子具有非常短的生命周期,但我们希望在它们“到期”时发生某些事情(比如递增整数x
)但我们仍然想要回收它们。现在,假设我们希望能够指定x
。但是,现在我们做什么了?
在移动中,我们希望能够调用函数来增加变量,但该变量必须波动。我们不希望将它放入析构函数中,因为这将涉及在编译时派生精确函数调用的模板,或者我们需要一个std::function
或函数指针来引用粒子内部的函数,浪费空间。我们想要做的是能够接受到期值,做一个动作,然后转发它。 换句话说,我们想要一个具有副作用的传出移动,特别是从左值到右值的转换。
您执行此操作的重要性 - 左值转换左值或使用operator=
或operator()
接收到另一个粒子时。你可以在一个对象接收到一个值时或者当你使用rvalue时这样做。但是假设我们想为许多不同类型的对象做这个 - 你想为5个不同的类中的每一个写5个或更多不同的移动函数吗? ,或者我们应该使用外部模板化函数对类型进行参数化?
你还怎么做?你仍然会在对象内部使用std::move()
,但我们希望将它与对象外部的函数耦合,因为这会代表移动的副作用。
Coliru:http://coliru.stacked-crooked.com/a/0ff11890c16f1621
#include <iostream>
#include <string>
struct Particle {
int i;
};
template <typename T>
T&& move( T& obj, int (*fn)(int) , int& i ) {
i = fn(i);
return(std::move(obj));
}
int increment(int i) { return i+1; }
int main() {
// Have some object pool we want to optimize by moving instead of creating new ones.
// We'll use rvalue semantics so we can "inherit" lifetime instead of copying.
Particle pool[2000];
// Fill up the "particles".
for (auto i = 0; i < 2000; ++i) {
pool[i].i = i;
}
// Perform the moves with side effects.
int j = 0;
for (auto i = 0; i < 1999; ++i) {
pool[i+1] = move<Particle>(pool[i], &increment, j);
std::cout << "Moves performed: " << j << '\n';
}
}
答案 1 :(得分:-1)
有时,使用一个返回*this
作为l值引用的方法会很方便,这样就可以将临时函数传递给接受l值引用的函数。
func(foo_t().lval_ref());
那么,人们为什么要这样做呢?假设一个函数将l值引用作为输出变量。如果调用者实际上不需要这个输出,那么传递临时代替而不是定义一些虚拟变量unused
,然后static_cast<void>(unused);
以禁止任何未使用变量的警告将是方便的。
类似地,可能希望有一个方法返回*this
作为r值引用,其使用方式与std::move()
相同。这样做可以提供更大的灵活性。你可以在方法实现中做任何你想要的棘手的事情: - )