“指向成员的智能指针”的真实示例是啥?
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)
交换含义。相同的智能x
和y
可以处理不同类型的数据(矩形、点、向量),甚至可以处理您不拥有的类型。
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)->decltype(auto) return t->x; ;
(注意 lambda 与你的相同),调用 @ 987654330@ 内部带有get_x(data)
而不是data->*x
,因此更容易实现相同的目标。或者是否可以通过扩展示例来激发->*
的使用(您提到它是简化的)?
重载->*
而不仅仅是将访问器作为lambda 传递的动机是什么?如果你能解释一下,那就太好了! @Yakk
@tobi 我不确定你在问什么。是的,每一行代码都可以用不同的方式重写。对于任何运算符+
或f(b)(a)
,a+b
始终可以重写为f(a, b)
。在这种情况下,x
表现为成员指针,使用成员指针语法是有意义的。
重载+
很常见,但很少使用->*
(即使没有重载)。那么您编写额外代码的故事是什么?历史(你曾经有raw mem ptrs 和重构)? raw 和 smart 成员 ptrs 使用相同的算法?我只是好奇...以上是关于“指向成员的智能指针”的真实示例是啥?的主要内容,如果未能解决你的问题,请参考以下文章