如何知道或测试给定类型是否要移动
How to know or test if a given type is going to be moved
我不是在为可移动类型寻找类型特征,也不是在寻找自动生成移动操作的规则。我正在寻找的是一般指南,以了解给定类型是否将被移动或复制,或者一种通过测试自己弄清楚的方法。
在某些情况下,移动操作是在用户不会注意到的情况下执行的,例如:
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 之前,上面的代码将产生从临时值到传递给 f
和 f_c
的std::string
副本,从 C++11 开始,std::basic_string
提供了一个移动构造函数(见这里 (8((,临时创建的代码被移动到传递给 f
和 f_c
的参数中。
有时用户试图使用 std::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
不会移动任何东西1:如果目标类型没有实现移动语义,它只会将左值转换为右值引用:不执行移动操作......上述return_by_value_x
函数中的 AFAIK std::move
会阻止编译器执行 RVO(我们正在恶化代码!
所以,在(也许不必要的(介绍之后,我会问我的问题:
如何知道或测试给定类型是否将被移动或复制?
这个问题是关于基本类型和复杂类型的:
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) { ... };
<小时 />- 基本类型可以移动吗? 有一些对
f_int
的调用,这意味着移动操作?-
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?
-
- 具有常量成员的复杂类型无法移动,不是吗?
-
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
是可移动的吗?-
f_weird({1, .0f, {0.d, 1.d}, {{{"a", 0ull}, {1u, 2u}}}}) // this moves?
-
- 如何自己测试上述情况以确定给定类型是否在给定上下文中移动?
1如果它被称为std::rvalref
或类似的东西不是更好吗?
如何自己测试上述情况以确定是否给定 类型是否在给定上下文中移动?
您可以测试派生类是否会将默认的移动构造函数定义为通过 SFINAE 删除。这个想法不适用于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>>;
演示。
Test
的移动构造函数是根据 [dcl.fct.def.default]/5 的默认移动构造函数。使上述工作的相关引用在 [class.copy]/11 中:
类
X
的默认 [..] 移动构造函数定义为 删除 (8.4.3( 如果X
有:
- 一个潜在的构造子对象类型
M
(或其数组(,由于重载分辨率 (13.3( 而无法移动 [..],作为 应用于M
的相应构造函数,导致歧义或 从默认值中删除或无法访问的函数 构造函数, [..]定义为已删除的默认移动构造函数将被重载解析 (13.3、13.4( 忽略。
对于初始化
Test(Test())
若要有效,由于复制 CTOR 不是隐式声明的,因此移动构造函数必须可用。 但是,根据上面的引用,如果基类(我们给定的T
(没有可调用的移动构造函数,则Test
的移动构造函数将被定义为已删除(因此被重载解析忽略(。(我有点不确定T
没有任何移动构造函数的情况,我将不胜感激,因为那里的标准得到了澄清。
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 检查函数返回类型是否与STL容器类型值相同
- 检查某些类型是否是模板类 std::optional 的实例化
- 表达式 SFINAE:如何根据类型是否包含具有一个或多个参数的函数来选择模板版本
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 如何检查模板类型是否可以从给定类型构造
- 用于检测函数类型是否为否的特征
- 了解类型是否可调用
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 键入特征以检查类型是否可从流和 MSVC 读取
- 从双精度转换为整数的显式类型是否始终检查整数溢出?
- 如何获取类型是否真正可移动可构造
- 在编译时检查类型是否为 std::basic_string<T> C++
- 在C++中,转换为simd类型是否有未定义的行为
- POD类型是否完全等同于琐碎的标准布局类型
- 聚合类型是否意味着它也是标准布局
- 有没有一种方法可以使用SFINAE来检测一个类型是否实现了给定的抽象基类
- 验证(使用 static_assert)元组类型是否遵循某种顺序(有状态编译时检查)
- 强制转换为不相关的引用类型是否违反严格的别名规则?
- 特征:从数组类型中获取标量类型是否记录?