This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [c++0x] unique_ptr.hpp implementation


On 8/14/07, Chris Fairles <chris.fairles@gmail.com> wrote:
> On 8/13/07, Howard Hinnant <hhinnant@apple.com> wrote:
> >
> > On Aug 12, 2007, at 5:52 PM, Jonathan Wakely wrote:
> >
> > > Both these problems can be avoided by getting rid of the
> > > specialisation using enable_if.  See how the EBO is used in the
> > > libstdc++ container types for a safe alternative e.g. _Vector_impl in
> > > bits/stl_vector.h.
> >
> > Or for the more ambitious, put the compressed_pair optimization into
> > tuple (which is really pretty easy given variadic templates), and
> > then have unique_ptr<T, D> hold a tuple<pointer, D> as a data
> > member.  The great thing about this solution is that it solves the
> > empty member problem once and for all.
> >
>
> Excellant idea. I took a stab. I got this to work:
>
> struct deleter { void operator()(int * p) { delete p; } };
> int * i = new int;
> tuple<int*,deleter> t(j,deleter());
> static_assert(sizeof(t) == sizeof(int*),"");
> get<1>(t)(get<0>(t));
>
> However, EBO only kicks in when theres only one instance of each empty
> type int the tuple (i.e. sizeof(tuple<deleter, deleter>) == 2 when I'd
> like it to be 1).
>
> I did something like this (same old type-traited class specialization
> selection idiom i seem to always use):
>
> template<int _Idx, typename _Head, bool _IsEmpty>
> struct _Head_base;
>
> template<int _Idx, typename _Head>
> struct _Head_base<_Idx, _Head, true> : public _Head
> { _Head& _M_head() { return *static_cast<_Head*>(this); } ... };
>
> template<int _Idx, typename _Head>
> struct _Head_base<_Idx, _Head, false>
> { _Head& _M_head() {return _M_head_impl; } ... _Head _M_head_impl; };
>
> template<int _Idx, typename _Head, typename... _Tail>
> struct _Tuple_impl<_Idx, _Head, _Tail...>
> : public _Tuple_impl<_Idx + 1, _Tail...>,
>   private _Head_base<_Idx, _Head, is_empty<_Head>::value> {
> typedef _Head_base<_Idx, _Head, std::is_empty<_Head>::value> _Base;
> _Head& _M_head() { return _Base::_M_head(); }
> ...
> };
>
> Using inheritance again blows up with types that have virtual
> overloads for _M_tail() and _M_head() accessors (violation of std of
> course using underscore + capital letter).
>
> I'm slightly stumped why ebo doesnt apply to tuple<empty,empty>. If I
> follow the recursion (H = _Head_base, T = _Tuple_impl, => means
> inherits from, comma separated bracket list) then:
>
> tuple<A,A> => T<0,A,A> => [ T<1,A> => [ T<0>, H<1,A,true> => A ],
> H<0,A,true> => A ]
> vs.
> tuple<A,B> => T<0,A,B> => [ T<1,B> => [ T<0>, H<1,B,true> => B ],
> H<0,A,true> => A ]
>
> Is it because T<0,A,A> has two paths to A and the ambiguity prevents EBO?
> T<0,A,A> => H<0,A,true> => A
> T<0,A,A> => T<1,A> => H<1,A,true> => A
>
> Also, the following test case fails, haven't tracked down the specific
> reason (feel free to enlighten me if you can!):

I figured it out ... namespace issue. It works as expected.

> int i=0;
> make_tuple(ref(i)) = tuple<int>(1);
> assert(i == 1);
>
> In member function '_Tuple_impl<_Idx, _Head, _Tail ...>&
> _Tuple_impl<_Idx, _Head, _Tail ...>::operator=(const _Tuple_impl<_Idx,
> _UElements ...>&) [with _UElements = int, int _Idx = 0, _Head =
> std::reference_wrapper<int>, _Tail = ]':
> tuple.hpp:183:   instantiated from 'tuple<_Elements>&
> test::tuple<_Elements>::operator=(const tuple<_UElements ...>&) [with
> _UElements = int, _Elements = std::reference_wrapper<int>]'
> ( 183 = static_cast<_Inherited&>(*this) = __in;)
>
> tuple.hpp:146: error: no match for 'operator=' in '((_Tuple_impl<0,
> std::reference_wrapper<int> >*)this)->_Tuple_impl<0,
> std::reference_wrapper<int> >::<anonymous>._Head_base<_Idx, _Head,
> false>::_M_head [with int _Idx = 0, _Head =
> std::reference_wrapper<int>]() = ((const _Tuple_impl<0,
> int>*)__in)->_Tuple_impl<_Idx, _Head, _Tail ...>::_M_head [with int
> _Idx = 0, _Head = int, _Tail = ]()'
> (146 = _Base::_M_head() = __in._M_head();)
>
> Not sure if thats enough to discern the context in which the error occurs.
>
> > Whether the std::committee will permit the empty member optimization
> > on tuple or not, is another question I'm unsure of.  Though at the
> > moment I don't think that this optimization is forbidden in the
> > current working draft either.
> >
> > Also note LWG issue:
> >
> >    http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#673
> >
> > I have no idea at this point if these mods will make it into the
> > standard.  But they are reflected in my reference implementation.
> >
> > -Howard
> >
> >
> Cheers,
> Chris
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]