#include <iostream>
int main() {
bool b = true;
std::cout << std::is_same<decltype(!(!b)), bool>::value << "\n";
auto bb = (!(!b));
std::cout << std::is_same<decltype(bb), bool>::value << "\n";
}
Run Code Online (Sandbox Code Playgroud)
上面的代码使用不同的编译器有不同的结果。这是编译器错误还是我遗漏了什么?
确定表达式是否是C++中的右值或左值的最佳方法是什么?可能这在实践中没有用,但是因为我正在学习rvalues和lvalues,所以我认为is_lvalue如果在输入中传递的表达式是左值而其他函数返回true 会更好.
例:
std::string a("Hello");
is_lvalue(std::string()); // false
is_lvalue(a); // true
Run Code Online (Sandbox Code Playgroud) " Effective C++ "第3项说"尽可能使用const",它给出了一个例子:
const Rational operator*(const Rational& lhs,
const Rational& rhs);
Run Code Online (Sandbox Code Playgroud)
防止客户端犯下这样的暴行:
Rational a, b, c;
...
(a * b) = c; // invoke operator= on the result of a*b!
Run Code Online (Sandbox Code Playgroud)
但是,函数的非参考返回值是否已经是一个rvalue?那么为什么还要这么做呢?
很长一段时间以来,我认为三元运算符总是返回一个右值.但令我惊讶的是,事实并非如此.在下面的代码中,我没有看到返回值foo和三元运算符的返回值之间的区别.
#include <iostream>
int g = 20 ;
int foo()
{
return g ;
}
int main()
{
int i= 2,j =10 ;
foo()=10 ; // not Ok
((i < 3) ? i : j) = 7; //Ok
std::cout << i <<","<<j << "," <<g << std::endl ;
}
Run Code Online (Sandbox Code Playgroud) 处理这种情况最简洁的方法是什么:
func a() string {
/* doesn't matter */
}
b *string = &a()
Run Code Online (Sandbox Code Playgroud)
这会生成错误:
不能取一个()的地址
我的理解是,如果采用地址,Go会自动将局部变量提升到堆中.这里很清楚,要采用返回值的地址.处理这个问题的惯用方法是什么?
过去几年我一直用C++编写代码.但有一个问题我无法弄清楚.我想问一下,C++,rvalues都是临时工吗?
如果不是,任何人都可以提供一个例子,其中代码中的临时生成是左值?
我听过斯科特迈耶斯说" std::move()什么都不动"......但我还没明白这意味着什么.
所以要指出我的问题,请考虑以下事项:
class Box { /* things... */ };
Box box1 = some_value;
Box box2 = box1; // value of box1 is copied to box2 ... ok
Run Code Online (Sandbox Code Playgroud)
关于什么:
Box box3 = std::move(box1);
Run Code Online (Sandbox Code Playgroud)
我确实理解左值和左值的规则,但我不明白的是记忆中实际发生了什么?它只是以某种不同的方式复制价值,共享地址或什么?更具体地说:什么使移动比复制更快?
我只是觉得理解这一点会让一切都清楚.提前致谢!
编辑:请注意,我不是在询问std::move()实现或任何语法的东西.
有没有办法在C++中编写一个接受左值和右值参数的函数,而不是模板?
例如,假设我编写了一个print_stream从a 读取istream并打印读取到屏幕的数据的函数.
我认为print_stream像这样打电话是合理的:
fstream file{"filename"};
print_stream(file);
Run Code Online (Sandbox Code Playgroud)
以及像这样:
print_stream(fstream{"filename"});
Run Code Online (Sandbox Code Playgroud)
但是我如何声明print_stream这两种用途都有效呢?
如果我声明它
void print_stream(istream& is);
Run Code Online (Sandbox Code Playgroud)
然后第二次使用将无法编译,因为rvalue不会绑定到非const左值引用.
如果我声明它
void print_stream(istream&& is);
Run Code Online (Sandbox Code Playgroud)
然后第一次使用将无法编译,因为左值不会绑定到右值引用.
如果我声明它
void print_stream(const istream& is);
Run Code Online (Sandbox Code Playgroud)
那么函数的实现将无法编译,因为你无法读取const istream.
我不能使该函数成为模板并使用"通用引用",因为它的实现需要单独编译.
我可以提供两个重载:
void print_stream(istream& is);
void print_stream(istream&& is);
Run Code Online (Sandbox Code Playgroud)
并且第二次调用第一次,但这似乎是很多不必要的样板,并且我发现每次用这样的语义编写函数时都必须这样做非常不幸.
我能做些什么吗?
我刚刚对那些(相当)新功能进行了一些研究,我想知道为什么C++委员会决定为它们引入相同的语法?似乎开发人员不必浪费一些时间来理解它是如何工作的,并且一个解决方案让我们考虑进一步的问题.在我的情况下,它从问题开始,可以简化为:
#include <iostream>
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(T&& a)
{
std::cout << "f(T&& a) for rvalues\n";
}
int main()
{
int a;
f(a);
f(int());
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我首先在VS2013上编译它,它按照我的预期工作,结果如下:
f(T& a) for lvalues
f(T&& a) for rvalues
Run Code Online (Sandbox Code Playgroud)
但有一个可疑的事情:intellisense强调了f(a).我做了一些研究,我明白这是因为类型崩溃(Scott Meyers将它命名为通用引用),所以我想知道g ++对它的看法.当然它没有编译.微软实现他们的编译器以更直观的方式工作是非常好的,但我不确定它是否符合标准,是否应该在IDE中存在这种差异(编译器与智能感知,但实际上可能存在在某种程度上是有道理的).好的,回到问题所在.我用这种方式解决了它:
template <typename T>
void f(T& a)
{
std::cout << "f(T& a) for lvalues\n";
}
template <typename T>
void f(const T&& a)
{
std::cout << "f(T&& a) for …Run Code Online (Sandbox Code Playgroud)