Why std :: shared_ptr does not have a & # 8594; *?

Why doesn't std :: shared_ptr have operator->* ?

Implementation will seem easy using variable templates.

See this document for more details.

Edit: this looks like a potential duplicate: About shared_ptr and a pointer to a member statement `β†’ *` and `std :: bind`

+6
source share
2 answers

This can be added to std::shared_ptr after C ++ 14 instead of the complex code you linked:

 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)...); }; } 

adding the SFINAE option is optional. Pay attention to the above committed forward, which is imperfect. It also supports strange types of "methods" for a specific extension if they produce somethung with operator() and nothing important.

This is still imperfect due to the imperfection of the perfect forwarding, so it may be a reason to leave it alone and force .get()->* instead. There are also some minor flaws in using lambda instead of class, but they can be fixed.

Solutions that clone an interface also have flaws (they can move twice instead of one or imply an exponential number of congestion).

Funny we can enter above ->* without changing 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)...); }; } } 

then using notstd::operator->* takes this into account. Interestingly, ->* does not have to be a non-stationary member of a class for its use, unlike many of its relatives (for example, -> and [] ).

I have included a similar one for unique_ptr , because why not.

An alternative would save shared_ptr in the returned lambda: it adds overhead in what looks like a low-level operation, so I didn’t, and it would be bad for unique_ptr if it were funny.

Now everything said is good and good, but does not answer the question.

A C ++ 03 shared ptr (say boost shared ptr) could add:

 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); } 

with ... emulated using macros (like boost ) or pattern code replication. It would not be ideal (two copies of each argument were made instead of one? I think we could replace args T with T const& args to fix this), but it would be difficult.

In comparison, in C ++ 11 it is simple. But std shared ptr was developed along with C ++ 11 and its predecessors that were developed before it. Thus, for the predecessors, adding ->* would be a lot of pain and a template for a small return, and C ++ 11 shared ptr was written based on these.

This part, however, is just an opinion or just that.

+4
source

If you want it, you can add it yourself. operator ->* is a regular binary operator , and, like operator + , it does not need to be a member.

Here is a slightly more general version that will add support ->* to all implementations of operator -> .

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

(The inferred return type is not suitable because it does not provide SFINAE, and then the template may interfere with other overloads. And, yes, the implementation above would be better if it forward ed rvalues. Finally, the <behavior cannot be captured without using recursive template.)

As for why shared_ptr does not provide it natively, member-pointers are simply forgotten. No other part of the standard library has operator ->* , although it would always be suitable for iterators, etc. There is also no functionality in the Boost.SmartPtr library that preceded the standard library. (Boost often has more bells and whistles.)

+2
source

Source: https://habr.com/ru/post/981185/


All Articles