r***s 发帖数: 737 | 1 在 template 里面,如何限定某个 class parameter 不能拷贝,只能移动?
例如下面的Baton类对象不能拷贝
template
class Holder {
Baton m_baton;
void Receive(Baton &&b)
{
m_baton = std::move(b);
}
} |
h**********c 发帖数: 4120 | 2 first time see this move()thing, 赶快跑了 |
N******K 发帖数: 10202 | 3 你不是已经写好了么?
【在 r***s 的大作中提到】 : 在 template 里面,如何限定某个 class parameter 不能拷贝,只能移动? : 例如下面的Baton类对象不能拷贝 : template : class Holder { : Baton m_baton; : void Receive(Baton &&b) : { : m_baton = std::move(b); : } : }
|
t**r 发帖数: 3428 | 4 你的問題有點模糊
你想disable 哪種copy? |
r***s 发帖数: 737 | 5 如果baton类里面定义了copy constructor,这里的move等于白搭。
【在 N******K 的大作中提到】 : 你不是已经写好了么?
|
r***s 发帖数: 737 | 6 还有几种copy? 定义了copy constructor 和 copy assign operator的类可以拷贝,
没定义或是删除了这两个函数的类不可拷贝。
我写这个模板的目的在于在一个系统中传递一个baton,比方说甲传给乙,此时乙手上
有接力棒,甲手上啥也没有。
但如果baton类是可拷贝的,甲乙手中都有一个baton的拷贝,这是不能容忍的。
【在 t**r 的大作中提到】 : 你的問題有點模糊 : 你想disable 哪種copy?
|
t**r 发帖数: 3428 | 7 你必須去改那個類,
for your reference:
#include
#include
struct A {
std::string s;
A() : s("test") {}
A(const A& o) : s(o.s) { std::cout << "move failed!n";}
A(A&& o) : s(std::move(o.s)) {}
};
A f(A a) {
return a;
}
struct B : A {
std::string s2;
int n;
// implicit move contructor B::(B&&)
// calls A's move constructor
// calls s2's move constructor
// and makes a bitwise copy of n
};
struct C : B {
~C() {}; // destructor prevents implicit move ctor C::(C&&)
};
struct D : B {
D() {}
~D() {}; // destructor would prevent implicit move ctor D::(D&&)
D(D&&) = default; // force a move ctor anyway
};
int main()
{
std::cout << "Trying to move An";
A a1 = f(A()); // move-construct from rvalue temporary
A a2 = std::move(a1); // move-construct from xvalue
std::cout << "Trying to move Bn";
B b1;
std::cout << "Before move, b1.s = "" << b1.s << ""n";
B b2 = std::move(b1); // calls implicit move ctor
std::cout << "After move, b1.s = "" << b1.s << ""n";
std::cout << "Trying to move Cn";
C c1;
C c2 = std::move(c1); // calls the copy constructor
std::cout << "Trying to move Dn";
D d1;
D d2 = std::move(d1);
}
【在 r***s 的大作中提到】 : 如果baton类里面定义了copy constructor,这里的move等于白搭。
|
r***s 发帖数: 737 | 8 好吧我没说明白,
http://www.stroustrup.com/bs_faq2.html#constraints
这个template将来是给别人用的,我当然可以在这里写注释
可是最好的办法是让编译器给报错。 Stroustrup给出了一些
例子。但是我不知道我这种情况怎么办
【在 t**r 的大作中提到】 : 你必須去改那個類, : for your reference: : #include : #include : struct A { : std::string s; : A() : s("test") {} : A(const A& o) : s(o.s) { std::cout << "move failed!n";} : A(A&& o) : s(std::move(o.s)) {} : };
|
h*****0 发帖数: 4889 | 9 cpp一般不能限定template arg的类型吧。换言之你最多要求是movable,不能要求不是
copable
如果你的某个类不允许拷贝,那就应该是那个类的定义里就不让。
【在 r***s 的大作中提到】 : 在 template 里面,如何限定某个 class parameter 不能拷贝,只能移动? : 例如下面的Baton类对象不能拷贝 : template : class Holder { : Baton m_baton; : void Receive(Baton &&b) : { : m_baton = std::move(b); : } : }
|
h*****0 发帖数: 4889 | 10 这种需求感觉应该传一个unique_ptr
【在 r***s 的大作中提到】 : 还有几种copy? 定义了copy constructor 和 copy assign operator的类可以拷贝, : 没定义或是删除了这两个函数的类不可拷贝。 : 我写这个模板的目的在于在一个系统中传递一个baton,比方说甲传给乙,此时乙手上 : 有接力棒,甲手上啥也没有。 : 但如果baton类是可拷贝的,甲乙手中都有一个baton的拷贝,这是不能容忍的。
|
|
|
G***l 发帖数: 355 | 11 你那个Receive里面应该用std::forward而不是std::move。std::move把任何value都
cast成rvalue,比如你有
string a = ...;
holder.Receive(a);
cout << a << endl;
在后面再用a的时候就会出错,因为a的内容已经被你悄悄的move到m_baton里了,但是
你在外面还能继续用a。别人,或者未来的你自己,看代码不会知道你在receive里面做
了什么,后面继续用a的话运行时就会挂掉。
std::forward会把lvalue保持lvalue,rvalue保持rvalue。上面那段code如果Receive
里面是std::forward的话m_baton会被用a来copy construct。后面接着用a不会出错。
如果你是调用holder.Receive(some_func_return_string());的话,m_baton会使用
move constructor来构造。
【在 r***s 的大作中提到】 : 在 template 里面,如何限定某个 class parameter 不能拷贝,只能移动? : 例如下面的Baton类对象不能拷贝 : template : class Holder { : Baton m_baton; : void Receive(Baton &&b) : { : m_baton = std::move(b); : } : }
|
h*****0 发帖数: 4889 | 12 你这个编不过的,Receive只接受右值
Receive
【在 G***l 的大作中提到】 : 你那个Receive里面应该用std::forward而不是std::move。std::move把任何value都 : cast成rvalue,比如你有 : string a = ...; : holder.Receive(a); : cout << a << endl; : 在后面再用a的时候就会出错,因为a的内容已经被你悄悄的move到m_baton里了,但是 : 你在外面还能继续用a。别人,或者未来的你自己,看代码不会知道你在receive里面做 : 了什么,后面继续用a的话运行时就会挂掉。 : std::forward会把lvalue保持lvalue,rvalue保持rvalue。上面那段code如果Receive : 里面是std::forward的话m_baton会被用a来copy construct。后面接着用a不会出错。
|
N******K 发帖数: 10202 | 13 baton里面没有 move constructor(&&) 和 move operator=(&&) ?
【在 r***s 的大作中提到】 : 如果baton类里面定义了copy constructor,这里的move等于白搭。
|
G***l 发帖数: 355 | 14 哦,我看错了,以为他那个function是template的,没注意是class template。那样就
没有问题了,只能用rvalue调用。
【在 h*****0 的大作中提到】 : 你这个编不过的,Receive只接受右值 : : Receive
|
N******K 发帖数: 10202 | 15 A=std::move(B)
如果 object没有 move operator=(&&) 就执行的是 copy operator=(const &)
【在 r***s 的大作中提到】 : 好吧我没说明白, : http://www.stroustrup.com/bs_faq2.html#constraints : 这个template将来是给别人用的,我当然可以在这里写注释 : 可是最好的办法是让编译器给报错。 Stroustrup给出了一些 : 例子。但是我不知道我这种情况怎么办
|
G***l 发帖数: 355 | 16 对的。必须要有move。如果不想一个class被copy/assign可以把copy禁掉。这样至少试
图copy的时候compiler会报错
【在 N******K 的大作中提到】 : A=std::move(B) : 如果 object没有 move operator=(&&) 就执行的是 copy operator=(const &)
|
N******K 发帖数: 10202 | 17 设置成private 或者 =delete
【在 G***l 的大作中提到】 : 对的。必须要有move。如果不想一个class被copy/assign可以把copy禁掉。这样至少试 : 图copy的时候compiler会报错
|
r***s 发帖数: 737 | 18 对, 但是想更general 一些
【在 h*****0 的大作中提到】 : 这种需求感觉应该传一个unique_ptr
|
a*********a 发帖数: 3656 | 19 in c++ 11:
template
class Holder {
std::static_assert(!std::is_copy_constructible::value);
std::static_assert(std::is_move_constructible::value);
Baton m_baton;
void Receive(Baton &&b) { m_baton = std::move(b); }
}
any Baton passed that is copy constructible, or is not move constructible
should cause a compilation error.
disclaimer: I have not used these traits, so you probably need to fiddle to
make it work.
anyhow check out type_traits. I did similar things before c++11 where I had
to
declare a static const bool trait on "Baton" classes myself (on other
characteristics of course).
【在 r***s 的大作中提到】 : 在 template 里面,如何限定某个 class parameter 不能拷贝,只能移动? : 例如下面的Baton类对象不能拷贝 : template : class Holder { : Baton m_baton; : void Receive(Baton &&b) : { : m_baton = std::move(b); : } : }
|
a*********a 发帖数: 3656 | 20 or a fun way to do it, something along the line.
template
bool copyable = std::is_copy_constructible::value>
class Holder {
Baton m_baton;
void Receive(Baton &&b) { m_baton = std::move(b); }
}
template
class Holder {
static_assert(false);
}
advantage is that it moves the clutter of static assertions out of the main
class body.
using the traits, you should not have to modify any of the Baton types.
disclaimer: not compiler tested. you likely need to fiddle. |
|
|
N******K 发帖数: 10202 | 21 m_baton = std::move(b); 用到的是operator=() 不是constructor
【在 a*********a 的大作中提到】 : in c++ 11: : template : class Holder { : std::static_assert(!std::is_copy_constructible::value); : std::static_assert(std::is_move_constructible::value); : Baton m_baton; : void Receive(Baton &&b) { m_baton = std::move(b); } : } : any Baton passed that is copy constructible, or is not move constructible : should cause a compilation error.
|
a*********a 发帖数: 3656 | 22 then use: std::is_copy_assignable::value
http://www.cplusplus.com/reference/type_traits/
plus, hopefully, the copy assignment is done with the copy-swap idiom. :)
【在 N******K 的大作中提到】 : m_baton = std::move(b); 用到的是operator=() 不是constructor
|
r***s 发帖数: 737 | 23 Exactly what I want
Thanks
【在 a*********a 的大作中提到】 : in c++ 11: : template : class Holder { : std::static_assert(!std::is_copy_constructible::value); : std::static_assert(std::is_move_constructible::value); : Baton m_baton; : void Receive(Baton &&b) { m_baton = std::move(b); } : } : any Baton passed that is copy constructible, or is not move constructible : should cause a compilation error.
|