是否存在与`std :: move`相反的作用的强制转换(或标准功能) [英] Is there a cast (or standard function) with the opposite effect to `std::move`

查看:83
本文介绍了是否存在与`std :: move`相反的作用的强制转换(或标准功能)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,这个问题不是对std :: move双重功能的重复项 std :: move的倒数是否存在?。我不是在问一种机制,以防止在原本会发生的情况下发生移动,而是进行复制;而是我要问的是一种使右值在将绑定到可修改左值引用的位置中被接受的机制。实际上,这与发明 std :: move 的情况正好相反(即,使可修改的左值在将要绑定到(可修改)右值引用)。

First off, this question is not a duplicate of Function dual to std::move? or of Does the inverse of std::move exist?. I am not asking about a mechanism to prevent moving in a situation where it would otherwise take place, and to copy instead; rather I am asking about a mechanism for making a rvalue being accepted in a position that is going to be bound to a modifiable lvalue reference. This is in fact the exact opposite of the situation for which std::move was invented (namely making a modifiable lvalue being accepted in a position that is going to be bound to a (modifiable) rvalue reference).

在我感兴趣的情况下,右值将不被接受,因为上下文需要一个可修改左值引用。由于某些原因,我不太了解,但愿意接受,一个(可修改的)右值表达式将绑定到一个恒定左值引用(无需引入其他临时变量),但是它赢了'不要绑定到可修改的左值引用(gcc给我的错误消息是类型为'A'的右值对类型为'A&'的非常量引用进行了无效的初始化,而c语为 non -const对 A类型的左值引用不能绑定到 A类型的临时对象;奇怪的是,我无法让这些编译器中的任何一个承认所讨论的表达式具有 A&&类型,即使该表达式实际上格式为 static_cast< A&>(...)本身不会引起错误)。我可以理解,通常情况下, 都不愿意在需要可修改的左值引用的位置接受右值表达式,因为这意味着通过该左值引用进行的任何修改都将丢失,而就像调用 std :: move 对编译器说:我知道这是一个左值,它将绑定到右值引用(参数),因此可能会被盗,但是我知道我在做什么,在这里还可以。我想说我知道这是临时的,它将绑定到可修改的左值引用(参数),因此将通过左值进行任何更改参考会消失,但是我知道我在做什么,在这里还可以。。

In the situation that interests me an rvalue will not be accepted, because the context requires a modifiable lvalue reference. For some reason that I don't quite understand but am willing to accept, a (modifiable) rvalue expression will bind to a constant lvalue reference (without introducing an additional temporary), but it won't bind to a modifiable lvalue reference (the error message that gcc is giving me is "invalid initialization of non-const reference of type ‘A&’ from an rvalue of type ‘A’ " while clang says "non-const lvalue reference to type 'A' cannot bind to a temporary of type 'A' "; curiously I cannot get either of these compilers to admit that the expression in question has type 'A&&', even if that expression actually is of the form static_cast<A&&>(...) which by itself raises no error). I can understand that one would not normally want to accept an rvalue expression in a position requiring a modifiable lvalue reference, since it implies that any modifications done via that lvalue reference will be lost, but just as calling std::move is saying to the compiler "I know this is an lvalue that is going to be bound to an rvalue reference (parameter) and therefore might be stolen from, but I know what I am doing and it is OK here" I would like to say in my case "I know this is temporary that is going to be bound to an modifiable lvalue reference (parameter) and therefore any changes that will be made through the lvalue reference will disappear unnoticed, but I know what I am doing and it is OK here".

我可以通过初始化一个 来解决问题。右值中类型为A的对象,然后在需要可修改的左值引用的地方提供名称。我认为这没有任何额外的运行时开销(无论如何,右值都需要一个临时的),但是必须这样做在几种方面很尴尬:必须引入一个虚拟名称,也许必须引入一个复合语句。保留声明,将产生右值的表达式与为其提供参数的函数调用分开。提出我的问题是否可以在不引入虚拟名称的情况下完成:

I can solve the problem by initialising a named object of type A from the rvalue, and then providing the name where a modifiable lvalue reference is needed. I don't think there is any extra runtime overhead for this (a temporary was needed for the rvalue anyway), but having to do this is awkward in several ways: having to introduce a dummy name, maybe having to introduce a compound statement just to hold the declaration, separating the expression producing the rvalue from the function call it is providing an argument for. Whence my question whether this can be done without introducing a dummy name:



  1. 有什么办法(例如使用类型转换)将类型A的右值表达式绑定到类型为A&的可修改左值引用

  2. 如果没有,则不引入A类型的命名对象吗? (如果可以,为什么?)如果存在,是否有与标准提供的类似于 std :: move 的机制配合使用?

  1. Is there any way (for instance using a cast) to bind an rvalue expression of type A to a modifiable lvalue reference of type A& without introducing a named object of type A?
  2. If there is not, is this a deliberate choice? (and if so, why?) If there is, is there a mechanism similar to std::move provided by the standard to facilitate it?


下面是简化的示例,其中我需要进行这种转换。我特意删除了A的特殊构造函数,以确保错误消息不涉及编译器决定引入的临时变量。当 A& 替换为 const A& 时,所有错误都会消失。

Here is a simplified illustration where I would need such a conversion. I deliberately removed the special constructors of A to be sure the error message do not involve temporaries that the compiler decided to introduce. All errors go away when the A& are replaced by const A&.

class A
{ int n;
public:
  A(int n) : n(n) {}
  A(const A&) = delete; // no copying
  A(const A&&) = delete; // no moving either
  int value() const { return n; }
};

int f(A& x) { return x.value(); }

void g()
{ A& aref0 = A(4); // error
  // exact same error with "= static_cast<A&&>(A(4))" instead of A(4)
  A& aref1 = static_cast<A&>(A(5)); // error
  // exact same error with "= static_cast<A&&>(A(5))" instead of A(5)
  f (A(6)); //error
  // exact same error with "= static_cast<A&&>(A(6))" instead of A(6)

  A a(7);
  f(a); // this works
  A& aref2 = a; // this works too, of course
}






对于那些想知道为什么我需要这个的人,这是一个用例。我有一个函数 f ,其参数用作输入参数,有时也用作输出参数,用更特殊的值替换提供的值(该值表示一个树状结构,以及一些不存在的分支可能已被填充);因此,此值作为可修改的左值引用传递。我还拥有一些全局变量,这些变量保存有有时用于为该参数提供值的值。这些值不可更改,因为它们已经完全专门化。尽管具有这种恒定的性质,但我过去通常不声明这些变量 const ,因为这会使它们不适合用作参数。但是实际上确实假定它们是全局常量和永久常量,因此我想重写代码以使其更明确,并且还避免了在更改 f (例如,当抛出异常时,它可能决定从其参数中移出;当参数表示一个无论如何都将被异常破坏的局部变量时,这将是可以的,但是如果将其绑定则将是灾难性的到全局常数)。因此,我决定在将这些全局常量之一传递给 f 时进行复制。有一个函数 copy 生成并返回这样的副本,我想调用它作为 f ; las copy(c)是一个右值,由于上述原因,它无法完成,尽管这种用法是绝对安全的,实际上比我以前的解决方案更安全。


For those who are wondering why I need this, here's one use case. I have a function f with a parameter that serves as input argument, and occasionally also as output argument, replacing the provided value by a "more specialised" value (the value represents a tree structure, and some absent branches might have been filled in); this value is therefore passed as a modifiable lvalue reference. I also have some global variables holding values that sometimes are used to provide a value for this argument; these values are unalterable because they are already completely specialised. In spite of this constant nature, I used to not declare these variables const, since that would make them unsuitable as argument. But they really are assumed to be global and perpetual constants, so I wanted to rewrite my code so as to make this explicit, and also avoid the possibility of accidentally making errors when changing the implementation of f (for instance it might decide to move from its argument when throwing an exception; this would be OK when the argument represents a local variable that is going to be destroyed by the exception anyway, but would be disastrous if it were bound to a global "constant"). I therefore decided to make a copy whenever passing one of these global constants to f. There is a function copy that makes and returns such a copy, and I would like to put a call to it as argument to f; alas copy(c) being an rvalue this cannot be done for the reasons explained above, even though this usage is perfectly safe, and in fact safer than my previous solution.

推荐答案

最简单的解决方案是:

template<typename T>
T& force(T&& t){
   return t;
}

这篇关于是否存在与`std :: move`相反的作用的强制转换(或标准功能)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆