首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++复制,移动构造函数

C++复制,移动构造函数
EN

Stack Overflow用户
提问于 2018-12-14 14:03:27
回答 2查看 4.2K关注 0票数 4

我这里有密码:

代码语言:javascript
复制
#include <string>
#include <iostream>
#include <initializer_list>

template <typename T>
class Test
{
public:
  Test(std::initializer_list<T> l)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Test(const Test<T>& copy)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
  Test(Test&&) = delete;
  Test() = delete;
};

void f(const Test<Test<std::string>>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void f(const Test<std::string>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  f(Test<Test<std::string>>{x});
}

int main()
{
  Test<std::string> t1 {"lol"};
  f(t1);
  return 0;
}

我尝试用GCC 7.3.0在我的linux 19上编译它,命令如下:

g++ -std=c++11 -O0 test.cpp -o -Wall -pedantic

编译失败,错误是此调用:

代码语言:javascript
复制
f(Test<Test<std::string>>{x});

需要移动构造函数,但它已被删除。我一直认为移动和复制构造函数在编译方面是等价的,因为rvalue可以绑定到const引用,但是在重载解析中,带有显式定义的rvalue引用的重载只是优先级。这是我第一次看到编译器实际上需要移动构造器,而不只是使用复制。为什么?我是不是遗漏了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-14 14:12:03

您显式地声明了move构造函数并将其标记为delete,它将被重载解析所选择,然后导致错误。

如果同时提供了复制和移动构造函数,并且没有其他构造函数是可行的,则如果参数是相同类型的rvalue ( xvalue,如std::move or a prvalue such as a nameless temporary (until C++17)的结果),则重载解析选择移动构造函数,如果参数是lvalue (命名对象或返回lvalue引用的函数/操作符),则选择复制构造函数。

请注意,重载解析忽略了explicitly-declared,但是-declared move constructor不会忽略。

重载解析忽略已删除的隐式声明的移动构造函数(否则将阻止rvalue中的复制初始化)。(自C++14以来)

票数 6
EN

Stack Overflow用户

发布于 2018-12-14 14:07:33

我一直认为移动和复制构造函数在编译方面是等价的,因为rvalue可以绑定到const引用,但是在重载解析中,带有显式定义的rvalue引用的重载只是优先级。

你在这个假设中是正确的。如果您有一个采用const&&&的重载集,则如果有rvalue,则&&版本将比const&更可取。这里的问题是您的&&版本被标记为已删除。这意味着您正在显式地声明您不希望在临时的情况下是可构造的,并且代码将无法编译。

在这种情况下,如果您不希望类是可移动的,那么您就可以摆脱

代码语言:javascript
复制
Test(Test&&) = delete;

因为您的用户定义的复制构造函数的存在将删除编译器自动生成的移动构造函数。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53781247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档