James Kanze
10/1/2008 8:16:00 AM
On Sep 30, 11:58 am, Hendrik Schober <spamt...@gmx.de> wrote:
> James Kanze wrote:
> > On Sep 29, 6:20 pm, Hendrik Schober <spamt...@gmx.de> wrote:
> >> I'm having two overloaded function templates,
> >> #include <iterator>
> >> template< typename T >
> >> void test( T /*a1*/, T /*a2*/ ) {}
> >> template< typename Iter >
> >> void test( Iter /*b*/, Iter /*e*/ ) {}
> >> which I need to call. (In reality, these are constructors,
> >> in case that matters.)
> > It could be critical, if you need the initialization list.
> The problem is more with your below idea: I cannot
> (easily) forward calls.
That's why I raised the issue of initialization lists. That's
the main reason I can think of why you might not be able to
forward calls. (It is, in fact, the only reason I can think of
why you might not be able to forward calls.)
> > [...]
> > But of course, since it's undefined behavior to instantiate
> > iterator_trais with anything that is neither an iterator nor a
> > pointer, you couldn't count on this even if the type deduction
> > trick worked.
> Is it?
I think so. In §17.4.3.6/2, it says:
In particular, the effects are undefined in the
following cases:
[...]
-- for types used as template arguments when
instantiating a template component, if the
operations on the type do not implement the
semantics of the applicable Requirements
subclause.[...]
I'm not sure, of course, because the description of Iterator
traits (§24.3.1) doesn't actually contain a Requirements
subclause. It does require a specific implementation, however
(with a partial specialization for pointers), and that
implementation uses typename Iterator::difference_type, etc. So
the presence of those types in the instantiation type would seem
to be a requirement. (In this regared, the definition of
iterator_category is probably the most significant; I can't
imagine anything but an iterator defining it.)
In practice, what I would expect is that the code would fail to
compile *IF* you use such an instantiation in a context which
requires a complete definition. Or, if that failure occured
during template type deduction, SFINAE. But I couldn't get it
to work.
> I thought std lib implementors must have faced this,
> but now I see that this
> #include <vector>
> int main()
> {
> const unsigned int ua[] = { 255, 255, 255, 255 };
> std::vector<int> v1(0u,1u);
> std::vector<int> v2(ua, ua+4);
> return 0;
> }
> fails spectacularly with Dinkumware (both call the ctor
> taking iterators), so I must be wrong.
The second is required to call the constructor taking iterators.
The first shouldn't, however; the standard says that if the
iterator type (determined by type deduction) is an integral
type, the constructor shall has the same effect as:
X( static_cast< typename X::size_type >( f ),
static_cast< typename X::value_type >( l ) ) ;
(This leads to some interesting, and possibly unintentional
effects, due to the fact that static_cast is an explicit
conversion. Thus:
std::vector< std::vector< int > > v( 10, 30 ) ;
works, although there is no implicit conversion of 30 to
std::vector< int >.)
The version of VC++ (which uses Dinkumware) which I have access
to gets this right. Some older implementations of the library
(Dinkumware or others), designed for compilers which didn't
support member templates, may have problems, however.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34