“指向成员的智能指针”的真实示例是啥?

Posted

技术标签:

【中文标题】“指向成员的智能指针”的真实示例是啥?【英文标题】:What is a real world example for "smart pointer to member"?“指向成员的智能指针”的真实示例是什么? 【发布时间】:2018-07-17 19:22:57 【问题描述】:

为了澄清英语中可能存在的优先级歧义:我们正在讨论“智能(指向成员的指针)”,而不是“指向成员的(智能指针)”。

我会将一个指向成员的智能指针定义为带有operator ->* (T* lhs, X rhs) 重载的类X。

在他的文章"Implementing operator->* for Smart Pointers" 中,Scott Meyers 只是简单地触及了 smart 指向成员的指针,因为当时(1999 年)具体问题对于 来说已经足够困难了raw 指向成员的指针(旁注:后者可以用 lambdas here 优雅地解决)。

无论如何,Scott Meyers 在脚注中写道:

在写完这篇文章的草稿后不久,我的一位顾问 客户向我展示了一个问题,该问题自然可以通过指向成员的智能指针来解决。我也很惊讶。

我试图为这种自然的指向成员的智能指针找到一个示例。 但我自己也想不出任何东西,在线搜索也没有找到我要找的东西。

你知道任何现实世界的“智能指针指向成员”的例子吗?

编辑: 我不是在寻找任何->* 过载(正如某些 EDSL 所做的那样)。 针对语义类似于内置->* 的示例,我上面的定义明确要求lhs 是一个原始指针

【问题讨论】:

序言清晰明了。 cppreference 提到它是“.. 实际上被 boost.phoenix 中的演员以这种身份使用。它在诸如 cpp.react 之类的 EDSL 中更常见。” 如果我们只能问他的咨询客户;) 即使在 SO 上也是一个有趣的例子***.com/q/23619152/8918119。但它们都不是真正的智能指针 在 cpp.react 示例中,->* 不用作通过指向成员的指针访问。他们只是在他们的 EDSL 中使用它,并且可以选择任何其他二元运算符。它与我的定义不符,因为 lhs 不是原始指针。 【参考方案1】:

您有一个布局引擎,应该可以旋转 90 度(高度和宽度交换)。

使用智能成员指针可以使(foo->*x)(foo->*y) 交换含义。相同的智能xy 可以处理不同类型的数据(矩形、点、向量),甚至可以处理您不拥有的类型。

template<class F>
struct smart_pm_t 
  F f;
  template<class T>
  friend decltype(auto) operator->*(T* t, smart_pm_t const& self ) 
    return self.f(t);
  
;

template<class F>
smart_pm_t<F> smart_pm( F f )  return std::move(f); 

auto x = smart_pm( [](auto* t)->decltype(auto) noexcept  return t->x;  );
auto y = smart_pm( [](auto* t)->decltype(auto) noexcept  return t->y;  );

我们可以和他们一起变得更好。

do_layout( data, x, y );

do_layout( data, y, x );

水平或垂直解决问题。

这是实际生产代码中的一个实际(简化)用例,它减少了代码重复并解决了一大堆错误,因为我们只需要修复代码一次。

右手普通成员指针的问题是我们必须传递一整套成员指针,每种类型一个在左侧工作。

实际上,我们编写了一个编译时多态成员指针。

【讨论】:

感谢@Yakk 提供的富有洞察力的示例。也许我遗漏了一些东西,但在我看来,这就像 lambda 调用周围的语法噪音:因为do_layout 无论如何都必须是一个模板,你可以只做auto get_x = [](auto* t)-&gt;decltype(auto) return t-&gt;x; ;(注意 lambda 与你的相同),调用 @ 987654330@ 内部带有get_x(data) 而不是data-&gt;*x,因此更容易实现相同的目标。或者是否可以通过扩展示例来激发-&gt;* 的使用(您提到它是简化的)? 重载-&gt;* 而不仅仅是将访问器作为lambda 传递的动机是什么?如果你能解释一下,那就太好了! @Yakk @tobi 我不确定你在问什么。是的,每一行代码都可以用不同的方式重写。对于任何运算符+f(b)(a)a+b 始终可以重写为f(a, b)。在这种情况下,x 表现为成员指针,使用成员指针语法是有意义的。 重载+ 很常见,但很少使用-&gt;*(即使没有重载)。那么您编写额外代码的故事是什么?历史(你曾经有raw mem ptrs 和重构)? rawsmart 成员 ptrs 使用相同的算法?我只是好奇...

以上是关于“指向成员的智能指针”的真实示例是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在多线程应用程序中使用屏障的真实示例是啥?

智能指针示例

第九课智能指针示例------狄泰软件学院

在链表中添加节点时使用双指针的原因是啥?

C++ 多重继承的真实例子是啥? [关闭]

使用std智能指针的正确方法来确保ptr安全