我不是在寻找 type trait for movable types , 也不 rules for automatic generation of move operations .我正在寻找的是了解给定类型是否要被 move 或复制的一般指南,或者是一种通过测试自行计算的方法。
在某些情况下, move 操作是在用户根本没有注意到的情况下执行的,例如:
void f(std::string) { ... }
void f_c(const std::string) { ... }
void g()
{
f(std::string("Hello world!")); // moved, isn't it?
f("Hello world!"); // moved, isn't it?
f_c(std::string("Hello world!")); // moved, isn't it?
f_c("Hello world!"); // moved, isn't it?
}
在 C++11 之前,上面的代码会在 std::string
中产生从临时值复制到传递给 f
的值和 f_c
, 从 C++11 开始 std::basic_string
提供一个 move 构造函数(参见 here (8) ),创建的临时对象被 move 到传递给 f
的参数中和 f_c
.
有时用户试图用 std::move
强制 move 语义功能:
std::string return_by_value_1()
{
std::string result("result);
return std::move(result); // Is this moved or not?
}
std::string return_by_value_2()
{
return std::move(std::string("result)); // Is this moved or not?
}
但是std::move
不 move 任何东西1:它只将左值转换为右值引用,如果目标类型没有实现 move 语义:不执行 move 操作...和 AFAIK std::move
在 return_by_value_x
上面的函数阻止编译器执行 RVO(我们正在恶化代码!)。
所以,在(可能是不必要的)介绍之后,我会问我的问题:
如何知道或测试给定类型是否要 move 或复制?
这道题是关于基本类型和复杂类型的:
int f_int(int) { ... };
template <typename F, typename S> void f_pair(std::pair<F, S>) { ... };
struct weird
{
int i;
float f;
std::vector<double> vd;
using complexmap = std::map<std::pair<std::string, std::uint64_t>, std::pair<std::uint32_t, std::uint32_t>>;
complexmap cm;
};
struct silly
{
std::vector<std::pair<const std::string, weird::complexmap>> vcm;
};
f_weird(weird) { ... };
f_silly(silly) { ... };
- 可以 move 基本类型吗?有一些电话打给
f_int
这意味着 move 操作?-
f_int(1); // this moves or construct an int in-place?
-
f_int(1 + 2); // this moves or construct an int in-place?
-
f_int(f_int(1) + 2); // this moves or construct an int in-place?
-
- 不能 move 具有 const 成员的复杂 类型,不是吗?
-
f_pair<std::pair<const std::string, int>>({"1", 2}); // unmovable?
-
f_pair<std::pair<std::string, std::string>>({"1", "2"}); // this moves?
-
f_silly({{{}, {}}}); // this moves?
-
struct weird
是可 move 的?-
f_weird({1, .0f, {0.d, 1.d}, {{{"a", 0ull}, {1u, 2u}}}}) // this moves?
-
- 如何自行测试上述情况以确定给定类型是否在给定上下文中 move ?
1如果叫std::rvalref
就更好了或类似的东西?
最佳答案
How to test by myself the above cases in order to determine if a given type is being moved in a given context?
您可以测试派生类是否会通过 SFINAE 将默认 move 构造函数定义为已删除。这个想法不适用于 final
类。一个似乎可行的粗略草图是
namespace detail {
// No copy constructor. Move constructor not deleted if T has an applicable one.
template <typename T>
struct Test : T { Test(Test&&) = default; };
}
// TODO: Implement unions
template <typename T>
using is_moveable = std::is_move_constructible<
std::conditional_t<std::is_class<T>{}, detail::Test<T>, T>>;
Demo .
Test
的 move 构造函数是根据 [dcl.fct.def.default]/5 的默认 move 构造函数。使上述工作有效的相关引用然后在 [class.copy]/11 中:
A defaulted [..] move constructor for a class
X
is defined as deleted (8.4.3) ifX
has:
- a potentially constructed subobject type
M
(or array thereof) that cannot be [..] moved because overload resolution (13.3), as applied toM
’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor, [..]A defaulted move constructor that is defined as deleted is ignored by overload resolution (13.3, 13.4).
用于初始化
Test(Test())
要有效,因为复制构造函数没有隐式声明, move 构造函数必须可用。然而,根据上面的引用,如果基类,我们给定的 T
,Test
的 move 构造函数将被定义为已删除(因此被重载决议忽略)没有可调用的 move 构造函数。 (我有点不确定 T
没有任何 move 构造函数的情况,我将不胜感激那里对标准的澄清。)
关于c++ - 如何知道或测试给定类型是否要 move ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28476393/