我不是在寻找type trait for movable types,也不是rules for automatic generation of move operations。我正在寻找的是一个通用指南,用于了解是否要移动或复制给定类型,或者通过测试自行计算。
在某些情况下,移动操作是在用户没有注意到的情况下执行的,例如:
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开始{ {1}}提供了一个移动构造函数(请参阅here (8)),并将创建的临时值移入传递给std::basic_string
和f
的参数中。
有时用户试图使用std::move
函数强制移动语义:
f_c
但是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?
}
没有移动任何 1 :它只将lvalues转换为rvalues引用,如果目标类型没有实现移动语义:没有移动操作是执行...以及上面std::move
函数中的AFAIK std::move
阻止编译器执行RVO(我们正在恶化代码!)。
因此,在(可能不必要的)介绍之后,我会问我的问题:
这个问题涉及基本类型和复杂类型:
return_by_value_x
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
1 如果它被称为f_weird({1, .0f, {0.d, 1.d}, {{{"a", 0ull}, {1u, 2u}}}}) // this moves?
或类似的东西会不会更好?
答案 0 :(得分:1)
如何自己测试上述情况以确定是否给定 是否在给定的上下文中移动了类型?
您可以测试派生类是否将通过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>>;
根据[dcl.fct.def.default] / 5,Test
的移动构造函数是默认的移动构造函数。进行上述工作的相关引用随后是[class.copy] / 11:
类
X
的默认[..]移动构造函数定义为 删除(8.4.3)如果X
有:
- 可能构造的子对象类型
M
(或其数组)由于重载解析(13.3)而无法移动[...],如 应用于M
的相应构造函数,导致歧义或 默认情况下删除或无法访问的功能 构造函数, [..]重载解析(13.3,13.4)忽略了定义为已删除的默认移动构造函数。
用于初始化
Test(Test())
有效,因为没有隐式声明复制ctor,移动构造函数必须可用。但是,根据上面的引用,Test
的移动构造函数将被定义为已删除(因此被重载解析忽略),如果基类(我们给定的T
)没有可调用的移动构造函数。 (我对T
没有任何移动构造函数的情况略感不确定,我很感激那里对标准的澄清。)