Algorithm template specialization problem

S

Sherrie Laraurens

Hi all,

I'm trying to write a generic algorithm routine that will
take begin and end iterators of a container, iterate through
the range and perform a "calculation" of sorts.

The trouble is that the algorithm will behave differently for
the two different types. I've considered calling the algorithm
foo_A and foo_B, but I don't like that approach because it will
blow out in naming complexity down the track.

I was hoping with partial specialisations, I could get something
happening, but I'm finding it difficult templating an iterator but
not knowing what "type" of iterator it is. Also another major
problem is the algorithm wont know what kind of type the classes
A or B will be specialised as.

I've considered using a function object, but the algorithm I'm trying
to perform is not a for_each style thing, it needs to go through all
the elements in the iterator range, do some things, then modify the
elements accordingly.

Some of the problem is see are:

1. Can't specialize on A or B properply without knowing their types
2. It would be unprofessional to have foo<T,A<T> >(v.begin,v.end)

below is what I've got so far, the code it pretty self explanatory,
but mind you it wont compile without errors.


template<typename T>
class A { public: T val; };

template<typename T>
class B { public: T val1; T val2; };

template< typename T,
typename P,
typename Iterator > class foo;


template<typename T, typename P = A<T>, typename Iterator>
class foo
{
void operator()(Iterator begin, Iterator end)
{
for(Iterator it = begin, it != end; it++)
{
(*it).val++;
}
}
};


template< typename T, typename P = B<T>, typename Iterator>
class foo
{
void operator()(Iterator begin, Iterator end)
{
for(Iterator it = begin, it != end; it++)
{
(*it).val1++;
(*it).val2++;
}
}
};


int main(void)
{
std::vector< A<double> > vec1(100,1);
foo< A<double> >()(vec1.begin(),vec1.end());

std::vector< B<double> > vec2(100,1);
foo< B<double> >()(vec2.begin(),vec2.end());

return true;
}


I was hoping someone could give me some good ideas, tips
or a way to get what I want happening. I would appreciate
it very much.




Sherrie
 
V

Victor Bazarov

Sherrie said:
I'm trying to write a generic algorithm routine that will
take begin and end iterators of a container, iterate through
the range and perform a "calculation" of sorts.

The trouble is that the algorithm will behave differently for
the two different types. I've considered calling the algorithm
foo_A and foo_B, but I don't like that approach because it will
blow out in naming complexity down the track.

I was hoping with partial specialisations, I could get something
happening, but I'm finding it difficult templating an iterator but
not knowing what "type" of iterator it is. Also another major
problem is the algorithm wont know what kind of type the classes
A or B will be specialised as.

I've considered using a function object, but the algorithm I'm trying
to perform is not a for_each style thing, it needs to go through all
the elements in the iterator range, do some things, then modify the
elements accordingly.

Sounds like a 'transform' analogue.
Some of the problem is see are:

1. Can't specialize on A or B properply without knowing their types
2. It would be unprofessional to have foo<T,A<T> >(v.begin,v.end)

below is what I've got so far, the code it pretty self explanatory,
but mind you it wont compile without errors.


template<typename T>
class A { public: T val; };

template<typename T>
class B { public: T val1; T val2; };

template< typename T,
typename P,
typename Iterator > class foo;


template<typename T, typename P = A<T>, typename Iterator>

You need to either move 'P' to the end or to give 'Iterator' its
default argument. I think you actually meant to specialise 'foo',
so here is what it should looke like:

template<typename T, typename Iterator>
class foo said:
class foo
{
void operator()(Iterator begin, Iterator end)
{
for(Iterator it = begin, it != end; it++)
{
(*it).val++;
}
}
};


template< typename T, typename P = B<T>, typename Iterator>

Same default argument problem here.
class foo
{
void operator()(Iterator begin, Iterator end)
{
for(Iterator it = begin, it != end; it++)
{
(*it).val1++;
(*it).val2++;
}
}
};

Add here
int main(void)
{
std::vector< A<double> > vec1(100,1);
foo< A<double> >()(vec1.begin(),vec1.end());

std::vector< B<double> > vec2(100,1);
foo< B<double> >()(vec2.begin(),vec2.end());

return true;
}


I was hoping someone could give me some good ideas, tips
or a way to get what I want happening. I would appreciate
it very much.

I don't know if it's going to give you any ideas (I hope it doesn't give
you the wrong ones :)) but it compiles for me on VC++ 2005 (although does
give some problems with Comeau online test:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<typename T>
class A { public: T val; A(T t) : val(t) {} };

template<typename T>
class B { public: T val1; T val2; B(T t) : val1(t), val2(0) {} };

template<typename Iterator, typename V> class foo;

template<typename Iterator, typename T>
class foo<Iterator, A<T> >
{
public:
void operator()(Iterator begin, Iterator end)
{
for (Iterator it = begin; it != end; it++)
{
(*it).val++;
}
}
};

template<typename Iterator, typename T>
class foo<Iterator, B<T> >
{
public:
void operator()(Iterator begin, Iterator end)
{
for(Iterator it = begin; it != end; it++)
{
(*it).val1++;
(*it).val2++;
}
}
};

template<typename Iterator>
void do_foo(Iterator it1, Iterator it2)
{
foo<Iterator, Iterator::value_type> ft;
ft(it1, it2);
}

#include <vector>

int main()
{
std::vector< A<double> > vec1(100,1);
do_foo(vec1.begin(),vec1.end());

std::vector< B<double> > vec2(100,1);
do_foo(vec2.begin(),vec2.end());

return true;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

V
 
B

benben

Maybe the following technique can help a bit:

class A{};
class B{};

template <typename T1, typename T2>
struct same_type
{
enum {result = 0};
};

template <typename T>
struct same_type<T, T>
{
enum {result = 1};
};

template <typename Itr>
void foo(Itr i, Itr f)
{
typedef
typename std::iterator_traits<Itr>::value_type
val_t;

if (same_type<val_t, A>::result) // specialize for type A
{
// ...
}
else if (same_type<val_t, B>::result) // specialize for B
{
// ...
}
else // non-specialized
{
// ...
}
}


Regards,
Ben
 

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,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top