草庐IT

c++ - 了解 `std::is_move_constructible`

coder 2023-06-02 原文

没有移动构造函数但具有接受 const T& 参数的复制构造函数的类型,满足 std::is_move_constructible。例如,在以下代码中:

#include <type_traits>

struct T {
    T(const T&) {}
    //T(T&&) = delete;
};

int main() {
    static_assert(std::is_move_constructible<T>::value, "not move constructible");
    return 0;
}

T 将没有隐式移动构造函数,因为它有一个用户定义的复制构造函数。

但是,如果我们取消注释移动构造函数的显式删除,代码将不再编译。为什么是这样?我本来希望显式复制构造函数仍然满足 std::is_move_constructible

重载是否起作用,选择声明的移动构造函数然后因为它被删除而失败?


如果标准规定了 no implicit move ctordeleted move ctor 类之间的移动构造性之间的差异,请引用,如果可能,请给出基本原理(例如“提供一种禁止移动施工的设施”——首先想到的就是)。

最佳答案

这是对我的第一个答案的全面修改,以纠正所说的一些错误并引用标准并指出提问者希望的一些细节。

什么std::is_move_constructible实际做

如果 T是一个结构然后std::is_move_constructible<T>计算结果为 std::is_constructible<T,T&&> . std::is_constructible<T,U>如果 T x(y) 则有效是一些 y 的格式良好的表达式类型 U .因此对于 std::is_move_constructible<T>说真的,T x(std::move(y)) y 的格式必须正确类型 T .

引用标准:

The predicate condition for a template specialization is_constructible<T, Args...>
shall be satisfied if and only if the following variable definition would
be well-formed for some invented variable t:
    T t(create<Args>()...);

(...)

Template: template <class T> struct is_move_constructible;
Condition: For a referenceable type T, the same result as is_constructible<T, T&&>::value,
           otherwise false.
Precondition: T shall be a complete type, (possibly cv-qualified) void,
              or an array of unknown bound.

创建移动构造函数时

标准规定,仅当用户未声明复制构造函数、移动构造函数、赋值运算符或析构函数时,才会创建默认移动构造函数。

If the definition of a class X does not explicitly declare a move
constructor, one will be implicitly declared as defaulted if and only if
—X does not have a user-declared copy constructor,
—X does not have a user-declared copy assignment operator,
—X does not have a user-declared move assignment operator, and
—X does not have a user-declared destructor

但是,该标准允许您使用类右值初始化类左值引用。

Otherwise, the reference shall be an lvalue reference to a non-volatile const type
(i.e., cv1 shall be const), or the reference shall be an rvalue reference.
—If the initializer expression is an xvalue (but not a bit-field),
class prvalue, array prvalue or function lvalue and “cv1 T1”
is reference-compatible with “cv2 T2”, or (...)
then the reference is bound to the value of the initializer expression (...)
(or, in either case, to an appropriate base class subobject).

因此,如果你有一个复制构造函数 T::T(S& other)和一个对象 y类型 T&& ,即对 T 的右值引用,然后 yT& 引用兼容和 T x(y)是调用复制构造函数的有效表达式 T::T(S&) .

示例结构的作用

让我以您的第一个示例为例,删除 const关键字,以避免十次声明引用需要比初始值设定项更具 cv 限定。

struct S {
    S(S&) {}
};

让我们检查一下情况。由于存在用户定义的复制构造函数,因此没有隐式默认的移动构造函数。然而, 如果 yS 类型,然后 std::move(y) , 类型为 S&& , 与类型 S& 的引用兼容.因此S x(std::move(y))完全有效并调用复制构造函数S::S(const S&) .

第二个例子做了什么

struct T {
    T(T&) {}
    T(T&&) = delete;
};

同样,没有定义移动构造函数,因为有一个用户定义的复制构造函数一个用户定义的移动构造函数。再次让 y类型为 T并考虑T x(std::move(y)) .

但是,这一次表达式中可以容纳多个构造函数,因此执行了重载选择。仅尝试使用最专业的匹配构造函数,因此只有移动构造函数 T::T(T&&)试图调用。但是move构造函数被删除了,所以这是无效的。

结论

第一个结构,S , 可以使用它的复制构造函数来执行类似移动的表达式,因为它是这个表达式最专业的构造函数。

第二个结构,T ,必须使用其显式声明的移动构造函数来执行类似移动的表达式,因为它是最专业的。然而,该构造函数被删除,移动构造表达式失败。

关于c++ - 了解 `std::is_move_constructible`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33939644/

有关c++ - 了解 `std::is_move_constructible`的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  4. ruby - 导轨 4 : column reference "updated_at" is ambiguous with Postgres - 2

    我正在尝试使用“updated_at”字段的日期时间范围查询数据库。前端在JSON数组中发送查询:["2015-09-0100:00:00","2015-10-0223:00:00"]在RailsController中,我使用以下方法将两个字符串解析为DateTime:start_date=DateTime.parse(params[:date_range_arr][0])end_date=DateTime.parse(params[:date_range_arr][1])#...@events=@events.where('updated_atBETWEEN?AND?,start_d

  5. ruby - what is - gets is a directory - 错误信息 - 2

    我遇到了这个奇怪的错误.../Users/gideon/Documents/ca_ruby/rubytactoe/lib/player.rb:13:in`gets':Isadirectory-spec(Errno::EISDIR)player_spec.rb:require_relative'../spec_helper'#theuniverseisvastandinfinite...itcontainsagame....butnoplayersdescribe"tictactoegame"docontext"theplayerclass"doit"musthaveahumanplay

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

  8. ruby-on-rails - 如何测试自己对 Ruby/ROR 的了解? - 2

    是否有self验证的问题列表。看着那个,我可以确定我知道。我应该复习一下。在学习的过程中,我列了一个这样的list,但它只包含我在某处听说过的项目。我需要一段时间才能找到新的东西。 最佳答案 以下是针对ruby​​和Rails的一些测试列表。证书名称:RubyonRails谁提供:oDeskIncorporation认证费用:免费网站:https://www.odesk.com/tests/985?pos=0证书名称:RubyonRails提供者:Techgig.com(TimesBusinessSolutionsLimited(T

  9. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  10. ruby-on-rails - 了解 "attribute_will_change!"方法 - 2

    我想覆盖store_accessor的getter。可以查到here.代码在这里:#Fileactiverecord/lib/active_record/store.rb,line74defstore_accessor(store_attribute,*keys)keys=keys.flatten_store_accessors_module.module_evaldokeys.eachdo|key|define_method("#{key}=")do|value|write_store_attribute(store_attribute,key,value)enddefine_met

随机推荐