在clang的C++ 11状态页面中遇到了一个名为"rvalue reference for*this"的提案.
我已经阅读了很多关于rvalue引用并理解它们的内容,但我认为我不知道这一点.我也无法使用这些条款在网上找到太多资源.
页面上的提案文件有一个链接:N2439(将移动语义扩展到*this),但我也没有从中获得太多的例子.
这个功能是什么?
C++ 11使得基于引用限定符重载成员函数成为可能:
class Foo {
public:
void f() &; // for when *this is an lvalue
void f() &&; // for when *this is an rvalue
};
Foo obj;
obj.f(); // calls lvalue overload
std::move(obj).f(); // calls rvalue overload
Run Code Online (Sandbox Code Playgroud)
我理解这是如何工作的,但它的用例是什么?
我看到N2819建议将标准库中的大多数赋值运算符限制为左值目标(即向赋值运算符添加" &"引用限定符),但这被拒绝了.所以这是一个潜在的用例,委员会决定不再使用它.那么,再一次,什么是合理的用例?
在Effective C++,第3项中,Scott Meyers建议重载operator*一个名为的类Rational:
class Rational { ... };
const Rational operator*(const Rational& lhs, const Rational& rhs);
Run Code Online (Sandbox Code Playgroud)
返回值被const限定的原因在下面的行中解释:如果不是const,程序员可以编写如下代码:
(a * b) = c;
Run Code Online (Sandbox Code Playgroud)
或者,更可能是:
if (a*b = c)
Run Code Online (Sandbox Code Playgroud)
很公平.现在我很困惑,因为我认为函数的返回值,这里是operator*,是一个rvalue,因此不能赋值.我认为它不是可转让的,因为如果我有:
int foo();
foo() += 3;
Run Code Online (Sandbox Code Playgroud)
那将无法编译invalid lvalue in assignment.为什么不在这里发生?有人可以对此有所了解吗?
编辑:我在Scott Meyers的那个项目上看到过很多其他线程,但是没有人解决我在这里暴露的rvalue问题.
我有一些swap为某些类实现的C++ 03代码,以便std::sort快速生成(和其他函数).
不幸的是,std::sort现在似乎使用了std::move,这意味着我的代码现在比C++ 03 慢得多.
我知道我可以#if __cplusplus >= 201103L用来有条件地定义一个move-constructor/move-assignment操作符,但是我想知道是否有更好的方法不使用预处理器hacks?
(我想避免使用预处理程序,因为它们会很难看,因为我不仅需要测试编译器版本_MSC_VER >= 1600,还因为它们不适用于像LZZ这样不能识别C++的工具11移动语法,但强迫我预处理代码.)
最近,我一直在开发一种在我的代码中做很多事情的做法const:
(1)功能论证,我知道永远不会改变.例如:
void foo (const int i, const string s)
^^^^^ ^^^^^
Run Code Online (Sandbox Code Playgroud)
(2)返回类型为const.例如:
struct A {
...
const int foo () { return ...; }
^^^^^
operator const bool () const { return ...; }
^^^^^
};
Run Code Online (Sandbox Code Playgroud)
(3)整数或字符串的平凡计算.例如:
const uint size = vec.size();
^^^^^
const string s2 = s1 + "hello ";
^^^^^
Run Code Online (Sandbox Code Playgroud)
......还有更多的地方.通常在其他现实世界的代码中,我没有看到标记为的这种小规模变量const.但我想,让它们const永远不会受到伤害.这是一个很好的编程习惯吗?
我希望在一些现有的c ++项目中使用一些c ++ 11特性,所以我开始在一些项目中更改Clang中的编译标志,并且我一直在遇到关于C++ 11处理转换操作符(或者转换)的特定问题运算符)我没想到会看到并且不明白为什么现在这被认为是一个错误,因为它是有效的C++代码而不是c ++ 11
我把它归结为这个简单的例子:
#include <iostream>
#include <vector>
class SerializableFormat
{
public:
size_t i;
};
class A
{
public:
size_t x, y;
A(size_t n) : x(n), y(1) { }
operator const SerializableFormat() const
{
SerializableFormat result;
result.i = x;
if (y)
{
result.i /= y;
}
return result;
}
};
int main(int argc, const char * argv[])
{
std::vector<SerializableFormat> v;
for(size_t i = 0; i < 20; i++)
{
v.push_back(A(i));
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
-std=c++98 …我注意到QMap::operator[](const Key & key)有这两个重载:
T & QMap::operator[](const Key & key)
const T QMap::operator[](const Key & key) const
Run Code Online (Sandbox Code Playgroud)
是否有理由按价值返回?
因为我们有移动语义:
当按值返回时,我们应该返回const值吗?
我问的原因是这样的:
想象一下,我们有:
class ExpensiveToCopy;
{
public:
int someProperty() const;
...
}
void f(const QMap<int, ExpensiveToCopy>& map)
{
int lala = map[4].someProperty(); // We need to copy the entire object
// just to look at someProperty();
}
Run Code Online (Sandbox Code Playgroud) 我认为这个问题有点被误解了.
回归const价值并不是可以被视为毫无意义的东西.正如Adam Burry在评论中指出的那样,Scott Meyers在更有效的C++(第6项)中推荐它,我将添加Herb Sutter的Exceptional C++(第20项,类机械,其相应的GotW 可在线获得).
这样做的理由是你希望编译器能够捕获像(a+b)=c(oops,意思==)或误导性语句这样的错别字a++++,这两种语句都被标记为开箱即用的原始类型int.因此,对于喜欢的东西operator+和operator++(int),返回const值有一定道理.
另一方面,正如已经指出的那样,返回a会const阻止C++ 11的移动语义,因为它们需要非const右值引用.
所以我的问题是,我们真的不能吃蛋糕吗?(我找不到办法.)
可能重复:
移动构造函数签名
struct X
{
X(X&); // (1)
X(X&&); // (2)
X(const X&); // (3)
X(const X&&); // (4)
};
Run Code Online (Sandbox Code Playgroud)
是否有任何情况(4)会在重载决议中被选中?
在我的代码中,我实现了Vector3的模板,如下所示:
template <typename T>
struct TVector3{
TVector3(const T& x, const T& y, const T& z); // normal constructor from x,y,z
TVector3(const T& val); // construct from a constant value
// .. other implementation
T x, y, z;
};
// and my overload operator+ for TVector3
template <typename T>
const TVector3<T> operator+(const TVector3<T>& lhs, const TVector3<T>& rhs)
{
return TVector3<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
}
Run Code Online (Sandbox Code Playgroud)
我期待这样的调用: (1,2,3)+ 1 =(2,3,4),所以我这样写了:
TVector3<float> v(1, 2, 3);
v + 1.0f; …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++11 ×7
const ×2
qualifiers ×2
c++-faq ×1
coding-style ×1
libc++ ×1
libstdc++ ×1
llvm ×1
overloading ×1
qt ×1
rvalue ×1
templates ×1
visual-c++ ×1