为什么std :: shared_ptr没有operator-> *?

时间:2015-01-18 18:47:57

标签: c++ shared-ptr variadic-templates

为什么std :: shared_ptr没有operator->*

使用可变参数模板看起来很容易。

有关详细信息,请参阅this paper

编辑:这似乎是:About shared_ptr and pointer to member operator `->*` and `std::bind`

的潜在副本

2 个答案:

答案 0 :(得分:4)

这可以在C ++ 14之后添加到std::shared_ptr,而不是你链接的复杂代码:

template<class Method>
auto operator->*(Method&& method){
  return [t=get(),m=std::forward<Method>(method)](auto&&args){
    return (t->*m)(std::forward<decltype(args)>(args)...);
  };
}

添加SFINAE可选。注意上面的完美前锋,这是不完美的。它还支持奇怪的&#34;方法&#34;类型到某个exten,只要它们产生一些operator()并且没有其他重要性。

由于完美转发的不完善,这仍然是不完美的,所以这可能是一个理由让它单独并强制.get()->*。使用lambda而不是类也存在一些细微的缺陷,但这些可以修复。

克隆界面的解决方案也有缺陷(它们可以移动两次而不是一次,或暗示指数级的重载)。

我们可以在不修改->*的情况下注入上述std

namespace notstd{
  template<class...Ts, class Method>
  auto operator->*(std::shared_ptr<Ts...> const& p, Method&& method){
    return [t=p.get(),m=std::forward<Method>(method)](auto&&args){
      return (t->*m)(std::forward<decltype(args)>(args)...);
    };
  }
  template<class...Ts, class Method>
  auto operator->*(std::unique_ptr<Ts...> const& p, Method&& method){
    return [t=p.get(),m=std::forward<Method>(method)](auto&&args){
      return (t->*m)(std::forward<decltype(args)>(args)...);
    };
  }
}

然后using notstd::operator->*将其考虑在内。有趣的是,->*不一定是类的非静态成员,因为它与许多亲戚(例如->[])不同,可以使用它。

我为unique_ptr添加了类似的内容,因为为什么不呢。

一个替代选项会将shared_ptr存储在返回的lambda中:它会增加看起来像低级别操作的开销,所以我没有这样做,而且在unique_ptr上它会被建议,如果有趣的话。

现在所有这些都很好,但没有回答这个问题。

C ++ 03共享ptr(比方说,boost shared ptr)可能已添加:

template<class T, class R, class...Args>
struct mem_fun_invoke; // details, exposes `R operator()(Args...)const`
template<class T, class D, class R, class...Args>
mem_fun_invoke<T,R,Args...>
operator->*(std::shared_ptr<Ts...> const& p, R(T::*Method)(Args...)){
  return mem_fun_invoke<T,R,Args...>(p.get(), Method);
}

使用宏(如...)或样板代码复制模拟boost。这不是完美的(每个arg的两个副本而不是一个?我想我们可以用T args替换T const& args来修复它,但这很难。

相比之下,在C ++ 11中很容易。但是std shared ptr是与C ++ 11一起设计的,它的前身是在它之前设计的。所以对于前体来说,添加->*会给很少的回报带来很多痛苦和困难,而C ++ 11共享ptr就是根据这些来编写的。

然而,这部分只是一个意见或一个故事。

答案 1 :(得分:2)

如果您需要,可以自己添加。 operator ->*ordinary binary operator,与operator +一样,does not need成为会员。

这是一个稍微更通用的版本,它会为实现->*的任何内容添加operator ->支持。

template< typename obj, typename ptm >
auto operator ->* ( obj && o, ptm && p )
-> decltype( o.operator -> () ->* p )
    { return o.operator -> () ->* p; }

(推断的返回类型不合适,因为它不提供SFINAE,然后模板可能会干扰其他重载。而且,是的,如果forward ed rvalues,上面的实现会更好。最后,如果不使用递归模板,则无法捕获operator -> shared_ptr。)

至于为什么operator ->*本身不提供它,指向成员的指针经常被遗忘。标准库的其他任何部分都没有{{1}},尽管它总是适用于迭代器等。 drill-down behavior库中的功能也不在标准库功能之前。 (提升通常有更多的花里胡哨。)