假设我有一个(普通的)类,它是可移动构造和可移动分配但不可复制构造或可复制分配:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
这很好用:
movable m1(movable(17));
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为m1它不是右值:
movable m2(m1);
Run Code Online (Sandbox Code Playgroud)
但是,我可以包m1中std::move,它投射到一个右值引用,以使其工作:
movable m2(std::move(m1));
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,假设我有一个(同样微不足道的)容器类,它包含一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用:
container<movable> c(movable(17));
Run Code Online (Sandbox Code Playgroud)
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨我正在尝试movable在container初始化列表中使用已删除的复制构造函数.同样,包裹value在std::move使得它的工作:
explicit container(T&& value) : value_(std::move(value)) {} …Run Code Online (Sandbox Code Playgroud) 我想知道如何做到以下几点
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
Run Code Online (Sandbox Code Playgroud)
如何传递rvalue引用并将其作为rvalue引用(可能包装)存储在调用包装器中?我知道我可以手动编写一个类似于std::reference_wrapper<>具有转换功能的类T&&,但我宁愿避免这种情况并使用标准技术.
我像AProgrammer推荐的那样实现了它:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Run Code Online (Sandbox Code Playgroud)
现在我可以说 …
众所周知,在大多数情况下,T&&意味着"这是一个临时对象".但是,如果想要从函数返回临时对象,他/她可以按如下方式声明函数:
template<class T>
T f()
{
T t;
......
return t;
}
Run Code Online (Sandbox Code Playgroud)
或(注意:不正确)
template<class T>
T&& f()
{
T t;
......
return t;
}
Run Code Online (Sandbox Code Playgroud)
但我认为后者是过度的,因为前者足够向后兼容.
然而,我也发现它std::forward()的返回类型被声明为T &&,所以我确信我对此的理解是不完整的.
我真正的问题是:我们何时何地将函数的返回类型声明为T &&?
该功能std::move()定义为
template<typename T>
typename std::remove_reference<T>::type&& move(T && t)
{
return static_cast<typename std::remove_reference<T>::type&&>( t );
}
Run Code Online (Sandbox Code Playgroud)
有四个地方我可以想象要调用的移动构造函数:
std::move()函数本身,但可能在返回的引用最终到达的位置.我敢打赌4号,但我不是百分百肯定,所以请解释你的答案.
假设我希望swap它适用于rvalues,并且不想为rvalue/lvalue引用的所有组合编写4个版本(rvalue/rvalue版本有点无意义,但它没有伤害).我想出了这个:
template <typename A, typename B>
struct is_same_no_ref
: std::is_same<
typename std::remove_reference<A>::type,
typename std::remove_reference<B>::type
>
{};
template <typename A, typename B,
typename = typename std::enable_if<is_same_no_ref<A, B>::value>::type
>
inline void my_swap(A&& a, B&& b) {
typename std::remove_reference<A>::type t = std::move(a);
a = std::move(b);
b = std::move(t);
}
Run Code Online (Sandbox Code Playgroud)
这似乎按预期工作.这个可以吗?或者我错过了一些让我后来受苦的重要事情?
UPDATE1: C++ 17构造附加型扣-这并不意味着自由功能是较差的溶液.
UPDATE2: C++ 17增加了保证副本省略(副本甚至没有在概念上发生).因此,使用C++ 17,我的代码实际上可以工作并具有最佳性能.但Martinho使用支撑初始化来获得返回值的代码仍然是我认为的更清洁的解决方案.但请查看Barry的回答以及TC的评论
旧帖子:类型推导不适用于构造函数(至少在包含C++ 11之前).常见的解决方案是依靠RVO(返回值优化)并编写make_XYZ模板函数,将其参数转发给构造函数.一个例子是std::make_tuple.
任何模板acrobat谁知道一个解决方法,以便在nocopy策略阻碍时使其工作?有效的解决方案仍然必须允许RVO发生.
另外,对于任何make_XYZ的要求是否会随C++ 14消失?
#include <iostream>
template <typename T>
struct XYZ
{
// remove following two lines to make the code compile
XYZ (XYZ const & rhs) = delete;
XYZ (XYZ && rhs) = delete;
T i;
XYZ (T i):i(i)
{
}
};
template <typename T>
XYZ<T> make_XYZ (T && i)
{
return XYZ<T>(std::forward<T>(i));
}
int main ()
{
auto x = make_XYZ(1);
std::cout << x.i << …Run Code Online (Sandbox Code Playgroud) 有可能辨别这两种方法吗?如果在这种情况下看起来完全可重复使用,是否应该改变右值?
TYPE a;
TYPE b = -a; // unary operator- of a TYPE& aka lvalue ref
TYPE c = -(a+b); // unary operator- of a TYPE&& aka rvalue ref
Run Code Online (Sandbox Code Playgroud) 我尝试A按如下方式定义一个类:
template< typename T >
class A
{
public:
A( T elem )
: _elem( elem )
{}
private:
TYPE _elem; // "TYPE" should be either "T" in case "elem" is an r-value or "T&" in case "elem" is an l-value.
};
Run Code Online (Sandbox Code Playgroud)
在这里,我希望_elem有一个类型T,以防构造函数的参数elem是一个r值或者T&case中的类型elem是一个l值.
有谁知道这是如何实现的?
#include <vector>
using namespace std;
struct A
{
vector<int> coll;
};
void f(const vector<int>&){}
void f(vector<int>&&){}
int main()
{
f(A().coll); // Is "A().coll" an xvalue?
}
Run Code Online (Sandbox Code Playgroud)
C++ 11保证f(A().coll)会打电话void f(vector<int>&&)吗?
为什么不能将rvalues转换为左值?但是可以在相反方向进行转换.技术上rvalues确实有内存地址,不是吗?
c++ ×10
rvalue-reference ×10
c++11 ×7
lvalue ×2
c++17 ×1
return-type ×1
rvalue ×1
stdbind ×1
swap ×1
temporary ×1