c++ - 如何知道或测试给定类型是否要 move

标签 c++ c++11 move-semantics

我不是在寻找 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::movereturn_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) if X has:

  • a potentially constructed subobject type M (or array thereof) that cannot be [..] moved because overload resolution (13.3), as applied to M’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 构造函数必须可用。然而,根据上面的引用,如果基类,我们给定的 TTest 的 move 构造函数将被定义为已删除(因此被重载决议忽略)没有可调用的 move 构造函数。 (我有点不确定 T 没有任何 move 构造函数的情况,我将不胜感激那里对标准的澄清。)

关于c++ - 如何知道或测试给定类型是否要 move ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28476393/

相关文章:

c++ - 使用c字符串从多项式c++中提取指数

c++ - 显示不在 3D 中的不移动文本(例如显示 HUD 或帧速率)

c++ - 具有模板化父类的派生类

c++ - 从基类实例调用派生类方法而无需强制转换

c++ - 具有 memory_order_relaxed 的存储是否有可能永远不会到达其他线程?

c++ - 因为我们有 move 语义,所以不需要为 STL 容器参数使用 const & 吗?

c++ - 错误 LNK2019 : unresolved external symbol (libJPEG compiling and linking)

c++ - 按值返回时,值参数是否隐式 move ?

c++ - 是否需要从字符串和 vector 中 move 以不拥有任何堆内存?

c++ - 具有函数模板的递归函数