std::exchange 不适用于 std::vector::reference 是否有技术原因,或者是 GCC 和 Clang 实现中的错误? 使用 MSVC 可以很好地编译。
我有这样的设置(最小示例)
struct Manager
{
std::vector<bool> lifeTimes;
//Should return the state before trying to kill it
bool kill(std::size_t index)
{
return std::exchange(lifeTimes[index], false);
}
};
std::exchange 会让这成为一个非常好的单行,但 GCC 抱怨:
错误:无法将“std::_Bit_reference&”类型的非常量左值引用绑定到“std::vector::reference”类型的右值(又名“std::_Bit_reference”)
所以它似乎抱怨
false
因为只有第二个参数是右值
这不是一个错误,MSVC 编译您的代码,因为它有一个扩展,可以将临时对象(右值)绑定到非常量左值引用。
下面的代码使用 MSVC 编译:
void foo(int& i) {}
foo(20); // you are passing Rvalue and it is bound to Lvalue reference
当您添加
const
来引用时,上述代码无法在 G++ 或 CLang 下编译
const Lvalue,它有效:
void foo(const int&){}
foo(20); // you can bind Rvalue to const Lvalue reference
关于向量的几句话。
operator[]
代表 vector<T>
,其中 T
是除 bool 之外的所有类型返回 T&
:
T& vector<T>::operator[](index) // where T is not bool
对于
bool
向量类模板具有专门化。存储 bool
的值以容纳一位空间,因为不能对一位使用取址运算符,vector<bool>::operator[](index)
无法返回引用。 vector<bool>
有内部 proxy 类来操作位(将此类称为 reference)。
vector<bool>::reference vector<bool>::operator[](index)
^^^^^^^^^
如您所见,proxy的对象是按值传递的。 所以当你打电话时
return std::exchange(lifeTimes[index], false);
您将临时对象(右值)传递给
exchange
,它通过引用非常量左值获取第一个参数。这就是 G++ 丢弃这段代码的原因。如果你想编译它,你可以显式创建 proxy 类的 Lvalue 对象并传递它:
bool kill(std::size_t index)
{
std::vector<bool>::reference proxyForBit = lifeTimes[index];
return std::exchange(proxyForBit, false);
}
根据已接受答案中的解释,从 C++17 开始,您可以使用
std::array
包装任何临时对象以获取对其的非常量引用:
std::exchange(std::array{lifeTimes[index]}[0], false)