how to cause const promotion for template code

S

Siemel Naran

Hi. I have a function

template <class InputIter, class OutputIter>
void f(InputIter begin, InputIter end, OutputIter result);

With c of type char* and cc of type const char*, the code f(c,c,cc) calls
f<char*, const char *>, which is fine.

But f(c,c,c) calls a new instantiation f<char*,char*> whereas I'd like it to
call f<const char*,char*>.

How to make this happen?
 
R

Rob Williscroft

Siemel Naran wrote in
in
comp.lang.c++:
Hi. I have a function

template <class InputIter, class OutputIter>
void f(InputIter begin, InputIter end, OutputIter result);

With c of type char* and cc of type const char*, the code f(c,c,cc)
calls f<char*, const char *>, which is fine.

Well a "char const *" *isn't* an output iterator, which isn't my
defenition of "fine".
But f(c,c,c) calls a new instantiation f<char*,char*> whereas I'd like
it to call f<const char*,char*>.

Why, what difference does it make ?. If you're trying to avoid code bloat
some modern compilers come with optimizers that can do this for you.
How to make this happen?

template < typename T >
inline void f( T *a, T *b, T *c )
{
f< T const *, T * >( a, b, c );
}

Rob.
 
S

Siemel Naran

Rob Williscroft said:
Siemel Naran wrote in

Well a "char const *" *isn't* an output iterator, which isn't my
defenition of "fine".

Why, what difference does it make ?. If you're trying to avoid code bloat
some modern compilers come with optimizers that can do this for you.

But some don't, so I have to do it.

template < typename T >
inline void f( T *a, T *b, T *c )
{
f< T const *, T * >( a, b, c );
}

First, can one specialize member functions? My function f is actually a
member function.

Second, how to handle STL iterators. For example, I want
f<std::deque<int>::iterator, std::deque<int>::iterator> to call
f<std::deque<int>::const_iterator, std::deque<int>::iterator>. Do you know
how to achieve this?

Thanks.
 
R

Rob Williscroft

Siemel Naran wrote in
in
comp.lang.c++:
But some don't, so I have to do it.

Do you know this for a fact, have you measured a performance drop
because of it ?
First, can one specialize member functions? My function f is actually
a member function.

The above isn't a specialization its an overload, and yes you can
overload member functions even when they are templates.

Also you can only explicitly specialze functions. eg:

template < typename T > void f( T ) {}
template said:
Second, how to handle STL iterators. For example, I want
f<std::deque<int>::iterator, std::deque<int>::iterator> to call
f<std::deque<int>::const_iterator, std::deque<int>::iterator>. Do you
know how to achieve this?

It can't be done as there is now way of getting a const_iterator
given *only* an iterator (except when the iterator is a pointer).

Rob.
 
D

Dietmar Kuehl

Siemel said:
First, can one specialize member functions? My function f is actually a
member function.

How is this question related to the above function? This is not a
specialization but an overload and you surely can overload member
functions. Other than this, the answer to your question is: no.
Actually, you can only fully specialize global functions while you
would require a partial specialization anyway.
Second, how to handle STL iterators. For example, I want
f<std::deque<int>::iterator, std::deque<int>::iterator> to call
f<std::deque<int>::const_iterator, std::deque<int>::iterator>.

Since there is no requirement that an iterator has a constant
counterpart, there is no requirement for something like
'const_iterator' in iterator traits. You might get away by
using your own traits class:

template <typename It> struct const_it { typedef It type; };
template <typename T> struct const_it<T*> { typedef T const* type; };
template <typename T, typename A>
struct const_it<std::deque<T, A>::iterator> {
typedef std::deque<T, A>::const_iterator type;
};
// ...

.... and use this in your function's implementation:

template <typename InputIter, typename OutputIter>
OutputIter f(InputIter beg, InputIter end, OutputIter to) {
return f<typename const_it<InputIter>::type, OutputIter>(beg, end,
to);
}

A complication is that 'std::vector<T>'s iterator may actually be
'T*' in which case you would attempt to specialize twice for the
type 'T*' if you added vector's iterator to the above specialization.
 
D

Dietmar Kuehl

Siemel said:
First, can one specialize member functions? My function f is actually a
member function.

How is this question related to the above function? This is not a
specialization but an overload and you surely can overload member
functions. Other than this, the answer to your question is: no.
Actually, you can only fully specialize global functions while you
would require a partial specialization anyway.
Second, how to handle STL iterators. For example, I want
f<std::deque<int>::iterator, std::deque<int>::iterator> to call
f<std::deque<int>::const_iterator, std::deque<int>::iterator>.

Since there is no requirement that an iterator has a constant
counterpart, there is no requirement for something like
'const_iterator' in iterator traits. You might get away by
using your own traits class:

template <typename It> struct const_it { typedef It type; };
template <typename T> struct const_it<T*> { typedef T const* type; };
template <typename T, typename A>
struct const_it<std::deque<T, A>::iterator> {
typedef std::deque<T, A>::const_iterator type;
};
// ...

.... and use this in your function's implementation:

template <typename InputIter, typename OutputIter>
OutputIter f(InputIter beg, InputIter end, OutputIter to) {
return f<typename const_it<InputIter>::type, OutputIter>(beg, end,
to);
}

A complication is that 'std::vector<T>'s iterator may actually be
'T*' in which case you would attempt to specialize twice for the
type 'T*' if you added vector's iterator to the above specialization.
 
S

Siemel Naran

Dietmar Kuehl said:
Siemel Naran wrote:
How is this question related to the above function? This is not a
specialization but an overload and you surely can overload member
functions. Other than this, the answer to your question is: no.

Why can one not specialize member functions?

Since there is no requirement that an iterator has a constant
counterpart, there is no requirement for something like
'const_iterator' in iterator traits. You might get away by
using your own traits class:

template <typename It> struct const_it { typedef It type; };
template <typename T> struct const_it<T*> { typedef T const* type; };
template <typename T, typename A>
struct const_it<std::deque<T, A>::iterator> {
typedef std::deque<T, A>::const_iterator type;
};
// ...

... and use this in your function's implementation:

template <typename InputIter, typename OutputIter>
OutputIter f(InputIter beg, InputIter end, OutputIter to) {
return f<typename const_it<InputIter>::type, OutputIter>(beg, end,
to);
}

A complication is that 'std::vector<T>'s iterator may actually be
'T*' in which case you would attempt to specialize twice for the
type 'T*' if you added vector's iterator to the above specialization.

Yes, this is a good idea. BTW, is the following legal in a fully ANSI
compliant compiler

template <typename Container>
struct const_it<typename Container::iterator> {
typedef typename Container::const_iterator type;
};

I guess not, because the compiler might have a hard time deducing
'Container' given a specialization const_it<MyIter>.


But it gets me thinking to a new solution.

template <class Container, class InputIter, class OutputIter>
void f(const Container&, typename Container::const_iterator begin, typename
Container::const_iterator end, OutputIter result);

We explicitly pass in the container in order that we can use
Container::const_iterator. There will be a specialization

template <class T, class OutputIter>
void f<const T*,const T*, OutputIter>(const T*, const T* begin, const T*
end, OutputIter result);
 
D

Dietmar Kuehl

Siemel said:
Why can one not specialize member functions?

Because it is sufficient to overload them.
BTW, is the following legal in a fully ANSI compliant compiler

template <typename Container>
struct const_it<typename Container::iterator> {
typedef typename Container::const_iterator type;
};

No: the container cannot be deduced if two containers share a common
iterator type. Still, the typedefs of related types may differ
for the two containers. The same is true for argument type deduction
in function templates: you cannot use a nested type.
But it gets me thinking to a new solution.

template <class Container, class InputIter, class OutputIter>
void f(const Container&, typename Container::const_iterator begin, typename
Container::const_iterator end, OutputIter result);

In this case, I'd go with a "range" which would be a pair of member
function ('begin()' and 'end()'; optionally also 'rbegin()' and
'rend()' for reversible ranges) plus a set of supporting typedefs.
The function would than just get one parameter for the input sequence,
namely the range.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top