草庐IT

c++ - 仅允许从引用到长期值(value)的隐式构造

coder 2024-02-11 原文

我已经实现了一个类型删除引用类,它可以从对任何类型的左值引用构造。但是,关于是否允许从 r 值构造,我遇到了一些进退两难的问题。

我遇到过两个用例:

  1. 将引用构造为局部变量

    int i = 42;
    Reference ref1 = i;   // This is allowed.
    Reference ref2 = 42;  // This should cause a compile error.
    
  2. 将引用构造为函数参数

    void func(Reference ref);
    
    int i = 42;
    func(i);   // This is allowed.
    func(42);  // This should also be allowed.
    

实际上,我想允许从任何生命周期大于引用的东西隐式构造一个 Reference 实例,但不允许从任何生命周期更短的东西中构造。

有什么方法可以做到这一点,即允许 func(42) 但不允许 ref = 42?我可以自由地对 Reference 进行任何必要的更改,但 func 的签名应该保持不变。

最佳答案

一般情况下你想要的是做不到的。

T&& 中删除 construct-from 是合理的,但是 T&& 不会转换为 T& 除非 T常量。这不允许函数参数大小写。

您可以为函数参数版本使用与局部变量版本不同的类型。

一个更通用的选择是从一个通用引用构建,如果您的参数是一个右值,则可以选择存储一个拷贝。

template<class T>
struct view_type_t {
  std::optional<T> possible_copy;
  T* ptr;
  view_type_t(T& t):ptr(std::addressof(t)) {}
  view_type_t(T&& t):
    possible_copy(std::forward<T>(t)),
    ptr(std::addressof(*possible_copy))
  {}
  view_type_t() = delete;
  // calls view_type_t&& ctor, possibly elided
  view_type_t(view_type_t const& src):
    view_type_t(
      src.possible_copy?
        view_type_t(T(*src.possible_copy)):
        view_type_t(*src.ptr)
    )
  {}
  // this is a bit tricky.  Forwarding ctors doesn't work here,
  // it MIGHT work in C++17 due to guaranteed elision
  view_type_t(view_type_t&& src) {
    if (src.possible_copy) {
      possible_copy.emplace(std::move(*src.possible_copy));
      ptr = std::addressof(*possible_copy);
    } else {
      ptr = src.ptr;
    }
  }
  view_type_t& operator=(view_type_t const& src); // todo
  view_type_t& operator=(view_type_t&& src); // todo
};

这模拟引用生命周期延长,其中临时生命周期由引用延长。这样的 Reference 的行为类似于 C++ 中的裸右值引用。

现在 Reference ref2 = 42; 起作用了,它现在是 42 的本地拷贝的引用。

我发现在制作其他类型的 View 类型时,这种技术比替代方法更好,例如 backwards_range,如果它是右值则保留其源范围的拷贝,如果它是右值则不保留左值。

这允许:

for( auto&& x : backwards( std::vector<int>{1,2,3} ) )

工作。更一般地说,如果 vector 是作为函数返回的临时创建的,我们可以对其进行反向调用并直接迭代;如果不创建本地拷贝,我们会遇到生命周期问题,因为临时对象的生命周期延长不会改变。

当然,您需要 C++17 之外的 std::optional 替换(例如 boost::optional)才能使上述代码正常工作。

关于c++ - 仅允许从引用到长期值(value)的隐式构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43323495/

有关c++ - 仅允许从引用到长期值(value)的隐式构造的更多相关文章

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

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

  2. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  3. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  4. 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.你能做的最好的事情是:

  5. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

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

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

  7. ruby - 允许主机名包含下划线的 URI.parse 的替代方法 - 2

    我正在使用DMOZ的listofurltopics,其中包含一些具有包含下划线的主机名的url。例如:608609TheOuterHeaven610InformationandimagegalleryofMcFarlane'sactionfiguresforTrigun,Akira,TenchiMuyoandotherJapaneseSci-Fianimations.611Top/Arts/Animation/Anime/Collectibles/Models_and_Figures/Action_Figures612虽然此url可以在网络浏览器中使用(或者至少在我的浏览器中可以使用:

  8. 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”]、[“苹果”、“

  9. ruby-on-rails - self 在 Rails 模型中的值(value)是什么?为什么没有明显的实例方法可用? - 2

    我的rails3.1.6应用程序中有一个自定义访问器方法,它为一个属性分配一个值,即使该值不存在。my_attr属性是一个序列化的哈希,除非为空白,否则应与给定值合并指定了值,在这种情况下,它将当前值设置为空值。(添加了检查以确保值是它们应该的值,但为简洁起见被删除,因为它们不是我的问题的一部分。)我的setter定义为:defmy_attr=(new_val)cur_val=read_attribute(:my_attr)#storecurrentvalue#makesureweareworkingwithahash,andresetvalueifablankvalueisgiven

  10. += 的 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=

随机推荐