I’m building a datastructure class with an std-like interface, and implementing different iterators for the data structure.
Conceptually, what I would like to do is something like this:
template <class DataT>
class DataStructure
{
protected:
DataT& Data;
public:
DataStructure(DataT& data) : Data(data) {}
class BaseIterator
{
public:
BaseIterator()
{
cout<<"BaseIterator"<<endl;
}
};
class DerrivedIterator1 : public BaseIterator
{
public:
DerrivedIterator1()
{
cout<<"DerrivedIterator1"<<endl;
}
};
class DerrivedIterator2 : public BaseIterator
{
public:
DerrivedIterator2()
{
cout<<"DerrivedIterator2"<<endl;
}
};
template<class IterT>
IterT Begin()
{
//none-specialized implementation. Possibly throw exception
}
template<>
DerrivedIterator1 Begin<DerrivedIterator1>()
{
//Find beginning for DerrivedIterator1
}
template<>
DerrivedIterator2 Begin<DerrivedIterator2>()
{
//Find beginning for DerrivedIterator1
}
};
But this of course does not compile since C++ doesn’t allow to specialize template member functions in none-specialized template containers.
The obvious workaround is of course to declare 2 different functions: Begin_Iterator1 and Begin_Iterator2 and be done with it. But I’m looking for a workaround that doesn’t change the interface.
Any ideas?
Edit: I forgot to mention that this is for a HW assignment and so boost and even std is not an option.
Function templates cannot be specialized in C++, point.
It does not matter whether they are members of template or not, specialization of function templates is not allowed. Normally when using argument types to infer the template arguments, overloading does the same specialization would, so specialization for functions (and the associated extra complexity in overload resolution and such) was not deemed necessary.
You however don’t have any arguments to infer on and would instantiate the templates manually. No,
would not work as you wrote the code, because type inference, just like overload resolution is only done on the arguments, not expected return value. You’d have to write:
and that has zero benefit over:
However, the first expression can be made to work with some wizardry. First you have to define
BeginIterator1andBeginIterator2and than you’d do a temporary to late-decide which one to construct:Now
dataStructure.Begin()will return a temporary something, that will callBeginIterator1if you cast it toDerivedIterator1or callBeginIterator2when you cast it toDerivedIterator2. If you pass it to something where the compiler can’t decide which one to cast to, it will die either because of ambiguous overload or becauseBeginIteratorConstructoris not in fact iterator and you’ll have to cast it explicitly.(You should carefully make as much of the
BeginIteratorConstructorprivate, but I am not sure how far will the compiler allow you to go, so you’d have to experiment a bit)