我正在使用MSVC,Visual Studio 2013.
假设我有一个结构:
struct my_pair {
int foo, bar;
};
Run Code Online (Sandbox Code Playgroud)
我想有效地添加一堆这些,而不是创建一个临时的,然后丢弃它:
vector<my_pair> v;
v.push_back(41, 42); // does not work [a]
v.push_back({41,42}); // works [b]
v.emplace_back(41,42); // does not work [c]
v.emplace_back({41,42}); // does not work [d]
v.emplace_back(my_pair{41,42}); //works [e]
Run Code Online (Sandbox Code Playgroud)
现在,如果我将构造函数和复制构造函数添加到我的代码中:
my_pair(int foo_, int bar_) : foo(foo_), bar(bar_)
{
cout << "in cstor" << endl;
}
my_pair(const my_pair& copy) : foo(copy.foo), bar(copy.bar)
{
cout << "in copy cstor" << endl;
}
Run Code Online (Sandbox Code Playgroud)
然后行为改变:
v.push_back(41, 42); // does not work [f]
v.push_back({41,42}); …Run Code Online (Sandbox Code Playgroud) 这是C++ 0x右值引用和临时值的后续问题
在上一个问题中,我询问了这段代码应该如何工作:
void f(const std::string &); //less efficient
void f(std::string &&); //more efficient
void g(const char * arg)
{
f(arg);
}
Run Code Online (Sandbox Code Playgroud)
由于隐式临时似乎应该调用移动重载,这种情况发生在GCC中,而不是MSVC(或MSVC的Intellisense中使用的EDG前端).
这段代码怎么样?
void f(std::string &&); //NB: No const string & overload supplied
void g1(const char * arg)
{
f(arg);
}
void g2(const std::string & arg)
{
f(arg);
}
Run Code Online (Sandbox Code Playgroud)
看来,基于我之前问题的答案,该函数g1是合法的(并且被GCC 4.3-4.5接受,但不被MSVC接受).但是,GCC和MSVC都拒绝,g2因为第13.3.3.1.4/3条禁止左值绑定到rvalue ref参数.我理解这背后的基本原理 - 在N2831"使用右值参考修复安全问题"中对此进行了解释.我也认为GCC可能正如该论文的作者所预期的那样实施该条款,因为GCC的原始补丁是由其中一位作者(Doug Gregor)撰写的.
但是,我不是很直观.对我来说,(a)a const string &在概念上更接近于string &&a const char *,而且(b)编译器可以创建一个临时字符串g2,就好像它是这样编写的:
void g2(const std::string & …Run Code Online (Sandbox Code Playgroud) 假设我有两个structs:
struct X {};
struct Y { X x; }
Run Code Online (Sandbox Code Playgroud)
我有功能:
void f(X&);
void f(X&&);
Run Code Online (Sandbox Code Playgroud)
我怎样写一个函数g()是需要Y&或Y&&只有完美的转发X&或X&&至f(),分别为:
template <typename T>
void g(T&& t) {
if (is_lvalue_reference<T>::value) {
f(t.x);
} else {
f(move(t.x));
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码说明了我的意图,但随着参数数量的增加,它的可扩展性不高.有没有办法让它完美转发并使其可扩展?
我认为我对rvalue引用并不十分了解.为什么以下错误无法编译(VS2012)'foo' : cannot convert parameter 1 from 'int' to 'int &&'?
void foo(int &&) {}
void bar(int &&x) { foo(x); };
Run Code Online (Sandbox Code Playgroud)
我会假设int &&从bar传递到foo时将保留该类型.为什么它会int在函数体内转换成一次?
我知道答案是使用std::forward:
void bar(int &&x) { foo(std::forward<int>(x)); }
Run Code Online (Sandbox Code Playgroud)
所以也许我只是没有清楚地掌握原因.(另外,为什么不std::move呢?)
#include <iostream>
using namespace std;
void func(int (&ref)[6]) { cout << "#1" << endl; }
void func(int * &&ref) { cout << "#2" << endl; }
int main()
{
int arr[6];
func(arr); // g++(5.4): ambiguous, clang++(3.8): #2, vc++(19.11): #1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这两个函数都是完全匹配.以下是标准的引用:
标准转换序列S1是比标准转换序列S2更好的转换序列
...
S1和S2是引用绑定(8.5.3),并且都不引用没有ref-qualifier声明的非静态成员函数的隐式对象参数,S1将rvalue引用绑定到rvalue,S2绑定左值引用.
这不是意味着第二个更好吗?
更新:
有一个相关的问题.以下代码是它的简化版本.
#include <iostream>
using namespace std;
void func(int *&) { cout << "#1" << endl; }
void func(int *&&) { cout << "#2" << endl; }
int main()
{
int arr[6]; …Run Code Online (Sandbox Code Playgroud) 我读到这this是一个右值,我们无法通过应用来获取其地址&this。
在我的代码中,我尝试使用的引用绑定this。我想知道哪种地址可以给this?还是都错了?
到底是this什么?左值,右值,关键字还是其他?
void MyString::test_this() const{
std::cout << "this: " << this << std::endl;
const MyString * const& this_ref = this;
std::cout << "thie_ref: " << &this_ref << std::endl;
const MyString * const&& this_right = this;
std::cout << "thie_right: " << &this_right << std::endl;
}
//this: 00CFFC14
//thie_ref: 00CFFB14
//thie_right: 00CFFAFC
Run Code Online (Sandbox Code Playgroud) 我发现lvaluelambda闭包始终可以作为rvalue函数参数传递。
请参见以下简单演示。
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void()>&& t)
{
}
int main()
{
// Case 1: passing a `lvalue` closure
auto fn1 = []{};
foo(fn1); // works
// Case 2: passing a `lvalue` function object
std::function<void()> fn2 = []{};
foo(fn2); // compile error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
情况2是标准行为(我只是std::function为了演示目的而使用a ,但是任何其他类型的行为都相同)。
案例1如何以及为什么起作用?fn1函数返回后关闭的状态是什么?
考虑以下:
struct vec
{
int v[3];
vec() : v() {};
vec(int x, int y, int z) : v{x,y,z} {};
vec(const vec& that) = default;
vec& operator=(const vec& that) = default;
~vec() = default;
vec& operator+=(const vec& that)
{
v[0] += that.v[0];
v[1] += that.v[1];
v[2] += that.v[2];
return *this;
}
};
vec operator+(const vec& lhs, const vec& rhs)
{
return vec(lhs.v[0] + rhs.v[0], lhs.v[1] + rhs.v[1], lhs.v[2] + rhs.v[2]);
}
vec&& operator+(vec&& lhs, const vec& rhs)
{
return move(lhs += …Run Code Online (Sandbox Code Playgroud) 我正在阅读托马斯·贝克尔关于右值参考及其使用的文章.在那里,他定义了他称之为if-it-a-name规则:
声明为右值引用的事物可以是左值或右值.区别标准是:如果它有一个名字,那么它就是一个左值.否则,它是一个右值.
这对我来说听起来很合理.它还清楚地标识了右值参考的右值.
我的问题是:
我正在努力理解rvalue参考文献.我看到他们是如何在构造函数中使用,之类的东西std::move和std::forward,但我还是不明白为什么这不起作用:
void func(string&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
Run Code Online (Sandbox Code Playgroud)
这样做:
template<typename T>
void func(T&& str)
{
cout << str << endl;
}
int main(int argc, char* argv[])
{
string s("string");
func(s);
}
Run Code Online (Sandbox Code Playgroud)
为什么它与函数模板版本一起使用?