Discussion:
[std-proposals] Pointer to pointer representation
t***@gmail.com
2018-10-29 07:00:15 UTC
Permalink
Hi,

If we have a container of unitque_ptr/shared_ptr objects, to reference to
them we can usethe follow notations:

*p->FuncMember();* //Same as *(*p).FuncMember();*

but, some times I need to create a pointer to this pointer and I use to
write the follow notation:

*(*p2p)->FuncMember();*

I think it will be a good idea if c++ could have a notation to this
situations like:

*p2p=>FuncMember() *//or

*p2p+>FuncMember()* //or

*p2p#>FuncMember()* //or

*p2p:>FuncMember()*

What do you think?

I hope I helped in some way.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/eeb29435-11b6-424e-8434-c0aeef0977f1%40isocpp.org.
m***@gmail.com
2018-10-29 21:46:08 UTC
Permalink
I don't think pointer-pointers are common enough to warrant adding their
own operator to the language when (*ptp)->FuncMember() and
**ptp.FuncMember() already work well enough.

I can think of 2 main situations where I've run into pointer pointers.
The first is functions that return a handle via an out param (which could
be replaced with an optional return val) and in those cases you wouldn't
typically be dereferencing the pointer-pointer in the body of the function,
and the calling function would probably only have a regular pointer
(passing the address of the pointer into the function).
The second case is iterators to pointers and in those cases it would often
better to use (*ptp)-> anyway so that the iterator type could change
without the dereference having to change.

I feel that pointer-pointers should be rare, and shouldn't get special
syntax when existing syntax works.
Post by t***@gmail.com
Hi,
If we have a container of unitque_ptr/shared_ptr objects, to reference to
*p->FuncMember();* //Same as *(*p).FuncMember();*
but, some times I need to create a pointer to this pointer and I use to
*(*p2p)->FuncMember();*
I think it will be a good idea if c++ could have a notation to this
*p2p=>FuncMember() *//or
*p2p+>FuncMember()* //or
*p2p#>FuncMember()* //or
*p2p:>FuncMember()*
What do you think?
I hope I helped in some way.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/988bb886-95a1-4484-9461-824368477145%40isocpp.org.
Itaj Sherman
2018-11-12 02:41:04 UTC
Permalink
Suppose you had a template function recursive_arrow_func(p) that
recursively applies operator-> on p, as
p.operator->().operator->().operator->() until it returns a pointer to an
object type that has no operator->

Then you could use it as:
recursive_arrow_func(p)->FuncMember();

Even if p was a pointer to pointer to pointer.

you could use this function to create one of several possible syntaxes,
using a keyword, say "arrows":

arrows(p)->FuncMember();
arrows[p]->FuncMember();
arrows{p}->FuncMember();
arrows--(p)->FuncMember();
arrows--[p]->FuncMember();
arrows(p).FuncMember();
arrows[p].FuncMember();
arrows{p}.FuncMember();
arrows--(p).FuncMember();
arrows--[p].FuncMember();

It could even do stuff like this:

template< typename T >
class my_ptr
{
private:
T* m;

public:
my_ptr(T* r) : m(r) {}

public:
T* operator->() const
{
return m;
}

T& operator*() const
{
return *m;
}
};


void g_test_recursive_arrow()
{
using element_t = std::pair< double, double >;
element_t a = { 1.5, 2.5 };

my_ptr< element_t > m = &a;
assert(a.first == arrows(m)->first);

my_ptr< my_ptr< element_t > > mm = &m;
assert(a.first == arrows(mm)->first);

my_ptr< my_ptr< my_ptr< element_t > > > mmm = &mm;
assert(a.first == arrows(mmm)->first);


element_t* p = &a;
assert(a.first == arrows(p)->first);

element_t** pp = &p;
assert(a.first == arrows(pp)->first);

element_t*** ppp = &pp;
assert(a.first == arrows(ppp)->first);


my_ptr< element_t >* pm = &m;
assert(a.first == arrows(pm)->first);

my_ptr< element_t* > mp = &p;
assert(a.first == arrows(mp)->first);


my_ptr< my_ptr< element_t >* > mpm = &pm;
assert(a.first == arrows(mpm)->first);

my_ptr< element_t* >* pmp = &mp;
assert(a.first == arrows(pmp)->first);

}



Here's a possible implementation.
I needed a traits 'has_arrow<T>' but I couldn't find it in boost, so I
used boost::has_dereference.
So classes with operator-> must has operator* to be usable.


namespace recursive_dereferencing {
namespace detail {


template <typename T>
class has_arrow
{
public: static const bool value = boost::has_dereference<T>::value;
};


template< typename T >
class recursive_arrow_result_impl;

template< typename T, bool >
class recursive_arrow_result_impl2
{
public: using type = typename recursive_arrow_result_impl<
std::invoke_result_t< decltype(&(T::operator->)), T > >::type;
};

template< typename T >
class recursive_arrow_result_impl2< T, false >
{
public: using type = T & ;
};

template< typename T >
class recursive_arrow_result_impl
{
public: using type = typename recursive_arrow_result_impl2<T,
has_arrow<T>::value >::type;
};

template< typename T >
class recursive_arrow_result_impl<T*>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};

template< typename T >
class recursive_arrow_result_impl<T&>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};

template< typename T >
class recursive_arrow_result_impl<T*&>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};

template< typename T >
using recursive_arrow_result_impl_t = typename
recursive_arrow_result_impl<T>::type;


template< typename T >
recursive_arrow_result_impl_t<T>
recursive_arrow_impl(T&& r
, typename std::enable_if< has_arrow< T >::value >::type* = NULL
)
{
return recursive_arrow_impl(std::forward<T>(r).operator->());
}

template< typename T >
T& recursive_arrow_impl(T& r
, typename std::enable_if< !has_arrow< T >::value >::type* = NULL
)
{
return r;
}

template< typename T >
recursive_arrow_result_impl_t<T*>
recursive_arrow_impl(T* r)
{
return recursive_arrow_impl(*r);
}


template< typename T >
using recursive_arrow_result_t = std::remove_reference_t<
recursive_arrow_result_impl_t< T > >*;

template< typename T >
recursive_arrow_result_t<T> recursive_arrow(T&& r)
{
return std::addressof(recursive_arrow_impl(std::forward<T>(r)));
}

}

template< typename T >
detail::recursive_arrow_result_t<T> recursive_arrow(T&& r)
{
return detail::recursive_arrow(std::forward<T>(r));
}

}


template< typename T >
std::invoke_result_t<
decltype(&recursive_dereferencing::recursive_arrow<T>), T&& >
recursive_arrow_func(T&& r)
{
return recursive_dereferencing::recursive_arrow(std::forward<T>(r));
}
Post by t***@gmail.com
Hi,
If we have a container of unitque_ptr/shared_ptr objects, to reference to
*p->FuncMember();* //Same as *(*p).FuncMember();*
but, some times I need to create a pointer to this pointer and I use to
*(*p2p)->FuncMember();*
I think it will be a good idea if c++ could have a notation to this
*p2p=>FuncMember() *//or
*p2p+>FuncMember()* //or
*p2p#>FuncMember()* //or
*p2p:>FuncMember()*
What do you think?
I hope I helped in some way.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/467a0621-ed78-4a96-b8f2-3485e059d840%40isocpp.org.
Itaj Sherman
2018-11-12 02:53:12 UTC
Permalink
...But I wholeheartedly recommend you don't do stuff like that.
Dereferencing is an important construction in the logic of your code. The
different between none, one or two dereferencing might be very meaningful
to a reader of the code - these differences should be readily explicit.
It might only make sense in extremely specialized situations, and I'd
recommend that it you ever use such function make sure it only compiles for
classes of a specialized concept.
Post by Itaj Sherman
Suppose you had a template function recursive_arrow_func(p) that
recursively applies operator-> on p, as
p.operator->().operator->().operator->() until it returns a pointer to an
object type that has no operator->
recursive_arrow_func(p)->FuncMember();
Even if p was a pointer to pointer to pointer.
you could use this function to create one of several possible syntaxes,
arrows(p)->FuncMember();
arrows[p]->FuncMember();
arrows{p}->FuncMember();
arrows--(p)->FuncMember();
arrows--[p]->FuncMember();
arrows(p).FuncMember();
arrows[p].FuncMember();
arrows{p}.FuncMember();
arrows--(p).FuncMember();
arrows--[p].FuncMember();
template< typename T >
class my_ptr
{
T* m;
my_ptr(T* r) : m(r) {}
T* operator->() const
{
return m;
}
T& operator*() const
{
return *m;
}
};
void g_test_recursive_arrow()
{
using element_t = std::pair< double, double >;
element_t a = { 1.5, 2.5 };
my_ptr< element_t > m = &a;
assert(a.first == arrows(m)->first);
my_ptr< my_ptr< element_t > > mm = &m;
assert(a.first == arrows(mm)->first);
my_ptr< my_ptr< my_ptr< element_t > > > mmm = &mm;
assert(a.first == arrows(mmm)->first);
element_t* p = &a;
assert(a.first == arrows(p)->first);
element_t** pp = &p;
assert(a.first == arrows(pp)->first);
element_t*** ppp = &pp;
assert(a.first == arrows(ppp)->first);
my_ptr< element_t >* pm = &m;
assert(a.first == arrows(pm)->first);
my_ptr< element_t* > mp = &p;
assert(a.first == arrows(mp)->first);
my_ptr< my_ptr< element_t >* > mpm = &pm;
assert(a.first == arrows(mpm)->first);
my_ptr< element_t* >* pmp = &mp;
assert(a.first == arrows(pmp)->first);
}
Here's a possible implementation.
I needed a traits 'has_arrow<T>' but I couldn't find it in boost, so I
used boost::has_dereference.
So classes with operator-> must has operator* to be usable.
namespace recursive_dereferencing {
namespace detail {
template <typename T>
class has_arrow
{
public: static const bool value = boost::has_dereference<T>::value;
};
template< typename T >
class recursive_arrow_result_impl;
template< typename T, bool >
class recursive_arrow_result_impl2
{
public: using type = typename recursive_arrow_result_impl<
std::invoke_result_t< decltype(&(T::operator->)), T > >::type;
};
template< typename T >
class recursive_arrow_result_impl2< T, false >
{
public: using type = T & ;
};
template< typename T >
class recursive_arrow_result_impl
{
public: using type = typename recursive_arrow_result_impl2<T,
has_arrow<T>::value >::type;
};
template< typename T >
class recursive_arrow_result_impl<T*>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};
template< typename T >
class recursive_arrow_result_impl<T&>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};
template< typename T >
class recursive_arrow_result_impl<T*&>
{
public: using type = typename recursive_arrow_result_impl< T >::type;
};
template< typename T >
using recursive_arrow_result_impl_t = typename
recursive_arrow_result_impl<T>::type;
template< typename T >
recursive_arrow_result_impl_t<T>
recursive_arrow_impl(T&& r
, typename std::enable_if< has_arrow< T >::value >::type* = NULL
)
{
return recursive_arrow_impl(std::forward<T>(r).operator->());
}
template< typename T >
T& recursive_arrow_impl(T& r
, typename std::enable_if< !has_arrow< T >::value >::type* = NULL
)
{
return r;
}
template< typename T >
recursive_arrow_result_impl_t<T*>
recursive_arrow_impl(T* r)
{
return recursive_arrow_impl(*r);
}
template< typename T >
using recursive_arrow_result_t = std::remove_reference_t<
recursive_arrow_result_impl_t< T > >*;
template< typename T >
recursive_arrow_result_t<T> recursive_arrow(T&& r)
{
return std::addressof(recursive_arrow_impl(std::forward<T>(r)));
}
}
template< typename T >
detail::recursive_arrow_result_t<T> recursive_arrow(T&& r)
{
return detail::recursive_arrow(std::forward<T>(r));
}
}
template< typename T >
std::invoke_result_t<
decltype(&recursive_dereferencing::recursive_arrow<T>), T&& >
recursive_arrow_func(T&& r)
{
return recursive_dereferencing::recursive_arrow(std::forward<T>(r));
}
Post by t***@gmail.com
Hi,
If we have a container of unitque_ptr/shared_ptr objects, to reference to
*p->FuncMember();* //Same as *(*p).FuncMember();*
but, some times I need to create a pointer to this pointer and I use to
*(*p2p)->FuncMember();*
I think it will be a good idea if c++ could have a notation to this
*p2p=>FuncMember() *//or
*p2p+>FuncMember()* //or
*p2p#>FuncMember()* //or
*p2p:>FuncMember()*
What do you think?
I hope I helped in some way.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f8cda263-6bfd-477e-b4eb-ad73f6c7e915%40isocpp.org.
Daniel Gutson
2018-11-12 03:37:13 UTC
Permalink
I can think of:

template<class T, unsigned int N>
indirections_type<T, N>::type

That would represent N indirections to an object of type T (this can be
easily done with TMP).

Then a function can be provided to dereference one of those types:

template<class T, unsigned int N>
T& dereference_indirections(indirections_type<T, N>::type ptr);

Would this solve your issue?
Post by t***@gmail.com
Hi,
If we have a container of unitque_ptr/shared_ptr objects, to reference to
*p->FuncMember();* //Same as *(*p).FuncMember();*
but, some times I need to create a pointer to this pointer and I use to
*(*p2p)->FuncMember();*
I think it will be a good idea if c++ could have a notation to this
*p2p=>FuncMember() *//or
*p2p+>FuncMember()* //or
*p2p#>FuncMember()* //or
*p2p:>FuncMember()*
What do you think?
I hope I helped in some way.
--
You received this message because you are subscribed to the Google Groups
"ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an
To view this discussion on the web visit
https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/eeb29435-11b6-424e-8434-c0aeef0977f1%40isocpp.org
<https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/eeb29435-11b6-424e-8434-c0aeef0977f1%40isocpp.org?utm_medium=email&utm_source=footer>
.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFdMc-0MkQhLbiY64uSYXd8U4URzkukz3beO3Hgrx9Ni8y7rBA%40mail.gmail.com.
Loading...