Topic: Sequence ctors from iterator range.


Author: James Kuyper <kuyper@wizard.net>
Date: 1998/11/30
Raw View
James Kuyper wrote:
>
> Valentin Bonnard wrote:
....
> > - there is no specialisation of functions (hum, at least
> >   I believe so, for member functions I don't know all
> >   the rules)
>
> See section 14.8: "Function template specializations". The title says it
> all, as far as this issue is concerned.

I know realize that what Valentin might have meant is that there is no
PARTIAL specialization of member functions. While attempting to refute
him, I came across the following in an example from section 14.7.3, p16:

 template<class T> struct A {
  void f(T);
  template<class X> void g(T,X);
  void h(T) { }
 };

 ...

 // member template partial specialization
 template<> template<class X> void A<int>::g(int,X);

However, that kind of partial specialization of a member function isn't
exactly the kind I was using. Also, it's in an example, which means it
isn't normative. Finally, the rest of the standard makes a clear
distinction between class templates and function templates, and
discusses partial specialization only in the context of member
templates.

Is partial specialization of member template functions supported, and if
not, why not?



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/11/28
Raw View
According to section 23.1.1, p11, one way to satisfy the sequence
constructor requirements of paragraph 9 is "to specialize the member
template for every integral type. Less cumbersome implmentation
techniques also exist."

Is the following one of those less cumbersome techniques? Have I got the
syntax right? My compiler doesn't implement partial specialization, so I
can't check it that way. Is there a better technique?

#include <memory> // for std::allocator<>
#include <numeric> // for std::numeric_traits<>

template<class T, class Allocator=std::allocator<T>> myseq
{
 typedef T   value_type;
 typedef Allocator::size_type size_type;
 // other members.

public:
 myseq(size_type n, const value_type& t,
  const Allocator &a=Allocator())
 {
  // Create new myseq containing n copies of t.
 }

private:
 template<bool Is_Integer, class InputIter, class Allocator>
 myseq(InputIter, InputIter, const Allocator&);

 template<class InputIter, class Allocator> // 23.1.1p4
 myseq<false, InputIter, Allocator>
  (InputIter i, InputIterator j,
  const Allocator&a=Allocator())
 {
  // create new myseq containing a copy of [i,j)
 }

 template<class InputIter, class Allocator>
 myseq<true, InputIter, Allocator> (InputIter f, InputIter l,
  const Allocator&a=Allocator())
  : myseq(static_cast<size_type>(f),
   static_cast<value_type>(l), a) {}

public:
 template<class InputIter>
 myseq(InputIter i, InputIter j,
   const Allocator&a=Allocator())
  : myseq<typename std::numeric_traits<InputIter>::is_integer,
    InputIter, Allocator> (i,j.a) {};
}


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/11/29
Raw View
James Kuyper wrote:

> According to section 23.1.1, p11, one way to satisfy the sequence
> constructor requirements of paragraph 9 is "to specialize the member
> template for every integral type. Less cumbersome implmentation
> techniques also exist."
>
> Is the following one of those less cumbersome techniques? Have I got the
> syntax right?

No:

- the class keyword is missing

- a ; is missing at the end

- typename is missing in typedef

- ctor don't recurse in C++: you can't call another ctor
  from a ctor

- there is no specialisation of functions (hum, at least
  I believe so, for member functions I don't know all
  the rules)

> template<class T, class Allocator=std::allocator<T>> myseq
> {
...
> public:
>         myseq(size_type n, const value_type& t,
>                 const Allocator &a=Allocator())
...
> private:
>         template<bool Is_Integer, class InputIter, class Allocator>
>         myseq(InputIter, InputIter, const Allocator&);
>
>         template<class InputIter, class Allocator>      // 23.1.1p4
>         myseq<false, InputIter, Allocator>
>                 (InputIter i, InputIterator j,
>                 const Allocator&a=Allocator())
...
>         template<class InputIter, class Allocator>
>         myseq<true, InputIter, Allocator> (InputIter f, InputIter l,
>                 const Allocator&a=Allocator())
>                 : myseq(static_cast<size_type>(f),
>                         static_cast<value_type>(l), a) {}
>
> public:
>         template<class InputIter>
>         myseq(InputIter i, InputIter j,
>                 const Allocator&a=Allocator())
>         : myseq<typename std::numeric_traits<InputIter>::is_integer,
>                         InputIter, Allocator> (i,j.a) {};
> }

The tradionnal trait classes and overloading tricks can be used;
looking at SGI STL 3:

First, the dispathing function

:>   // Check whether it's an integral type.  If so, it's not an
iterator.
:>   template <class _InIter>
:>   void _M_insert_after_range(_Node_base*
__pos,
:>                              _InIter __first, _InIter __last) {
:>     typedef typename _Is_integer<_InIter>::_Integral _Integral;
:>     _M_insert_after_range(__pos, __first, __last, _Integral());
:>   }

It's actually a fill request (count, value)

:>   template <class _Integer>
:>   void _M_insert_after_range(_Node_base* __pos, _Integer __n,
_Integer __x,
:>                              __true_type) {
:>     _M_insert_after_fill(__pos, __n, __x);
:>   }

It's actually a range [begin, end)

:>   template <class
_InIter>
:>   void _M_insert_after_range(_Node_base* __pos,
:>                              _InIter __first, _InIter __last,
:>                              __false_type) {
... insert the elements
:>   }

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/11/29
Raw View
Valentin Bonnard wrote:
>
> James Kuyper wrote:
>
> > According to section 23.1.1, p11, one way to satisfy the sequence
> > constructor requirements of paragraph 9 is "to specialize the member
> > template for every integral type. Less cumbersome implmentation
> > techniques also exist."
> >
> > Is the following one of those less cumbersome techniques? Have I got the
> > syntax right?
>
> No:
>
> - the class keyword is missing
>
> - a ; is missing at the end
>
> - typename is missing in typedef

Sorry about those! I know all of those rules; I introduced some typos
while doing cut-and-paste-and-remove-irrelevancies.

> - ctor don't recurse in C++: you can't call another ctor
>   from a ctor

It isn't recursion, it's just a function call, and calls to ctors are
allowed inside a ctor, in the initializer list. What I was thinking of
was a generalization of the syntax that allows you to call base class
ctors. Unfortunately, that generalization isn't in the standard :-( Such
initializers are restricted to base classes.

> - there is no specialisation of functions (hum, at least
>   I believe so, for member functions I don't know all
>   the rules)

See section 14.8: "Function template specializations". The title says it
all, as far as this issue is concerned.

I think I can recover my original idea by replacing:

> > template<class T, class Allocator=std::allocator<T>> myseq

with:

template<class T, class Allocator=std::allocator<T> > class myseq
 : protected baseseq

> > {
> ...
> > public:
> >         myseq(size_type n, const value_type& t,
> >                 const Allocator &a=Allocator())
> ...

Then I move the following ctors into baseseq, changing their names of
course:

> > private:
> >         template<bool Is_Integer, class InputIter, class Allocator>
> >         myseq(InputIter, InputIter, const Allocator&);
> >
> >         template<class InputIter, class Allocator>      // 23.1.1p4
> >         myseq<false, InputIter, Allocator>
> >                 (InputIter i, InputIterator j,
> >                 const Allocator&a=Allocator())
> ...
> >         template<class InputIter, class Allocator>
> >         myseq<true, InputIter, Allocator> (InputIter f, InputIter l,
> >                 const Allocator&a=Allocator())
> >                 : myseq(static_cast<size_type>(f),
> >                         static_cast<value_type>(l), a) {}
> >

And then initialize baseseq in the initializer list of the myseq ctor:

> > public:
> >         template<class InputIter>
> >         myseq(InputIter i, InputIter j,
> >                 const Allocator&a=Allocator())
> >         : myseq<typename std::numeric_traits<InputIter>::is_integer,
      baseseq-^^^^^
> >                         InputIter, Allocator> (i,j.a) {};
> > }

The technique you describe below has the disadvantage that the
is_integer decision is done at run-time, whereas my technique allows it
to be evaluated at compile time.

> The tradionnal trait classes and overloading tricks can be used;
> looking at SGI STL 3:
>
> First, the dispathing function
>
> :>   // Check whether it's an integral type.  If so, it's not an
> iterator.
> :>   template <class _InIter>
> :>   void _M_insert_after_range(_Node_base*
> __pos,
> :>                              _InIter __first, _InIter __last) {
> :>     typedef typename _Is_integer<_InIter>::_Integral _Integral;
> :>     _M_insert_after_range(__pos, __first, __last, _Integral());
> :>   }

That depends upon a specially-defined traits class, _Is_integer,
duplicating a feature of the numeric_limits<> traits class. This is OK
for a sequence class that is part of the STL, but for a user-defined
sequence class, numeric_limits<InputIter>::is_integer is better.

> It's actually a fill request (count, value)
>
> :>   template <class _Integer>
> :>   void _M_insert_after_range(_Node_base* __pos, _Integer __n,
> _Integer __x,
> :>                              __true_type) {
> :>     _M_insert_after_fill(__pos, __n, __x);
> :>   }
>
> It's actually a range [begin, end)
>
> :>   template <class
> _InIter>
> :>   void _M_insert_after_range(_Node_base* __pos,
> :>                              _InIter __first, _InIter __last,
> :>                              __false_type) {
> ... insert the elements
> :>   }



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]