Template specialisation of template class member function
What I am trying to do is get a piece of code like the following working:
Code:
template <typename T>
class BufferClass
{
public:
template <typename Iter_>
void assign(Iter_ first, Iter_ last)
{
//Do something
}
//But if it is a list containing any element type then...
template <>
void assign<typename std::list<T>::iterator >(
typename std::list<T>::iterator first,
typename std::list<T>::iterator last)
{
//Do something else
}
//...
private:
//.....
};
Now clearly, the above is wrong, because you cannot specialise the member function without fully specialising the enclosing class (that said, it rather annoyingly compiles under VS2005!:( ). The problem is, I have no idea what T will be, so, I cannot fully specialise the enclosing class (short of writing far more specialisations than I care to write - there has to be a better solution that this... I hope).
I have thought about creating a partially specialised nested class - as far as I know it's ok to partially specialise a member class without specialising the enclosing class. But, then again, that doesn't really help since it's the member function I'm trying to specialise.
Anyway, any ideas on how to create a 'legal' version of the above code would be much appreciated.
At the end of the day I don't want to have to use function overloading. i.e.
Code:
template <typename Iter_>
void assign(Iter_ first, Iter_ last)
{
//Do something
}
void assign(std::list<char>::iterator first, std::list<char>::iterator last)
{
//Do something
}
void assign(std::list<unsigned char>::iterator first,
std::list<unsigned char>::iterator last)
{
//Do something
}
void assign(std::list<short>::iterator first, std::list<short>::iterator last)
{
//Do something
}
void assign(std::list<unsigned short>::iterator first,
std::list<unsigned short>::iterator last)
{
//Do something
}
// etc ...
Re: Template specialisation of template class member function
You just need to create another template class with list as parameter in angle bracket.
Re: Template specialisation of template class member function
Re: Template specialisation of template class member function
I once had a similar problem and solved it by providing a non-member friend function (which can be specialized).
Re: Template specialisation of template class member function
What is it about std::list that makes it special?
If the assign function changes on iterator_category then could you specialise on that?
Where Iter_::iterator_category is bidirectional_iterator_tag or random_access_iterator_tag etc.
Re: Template specialisation of template class member function
Quote:
Originally Posted by GNiewerth
I once had a similar problem and solved it by providing a non-member friend function (which can be specialized).
Thanks for the suggestion - I had a play with this idea and it might just be my incompetence, but for this particular case I can't think of a way to do it without the requirement of partial specialisation of a non-member function, which is currently illegal. :(
Re: Template specialisation of template class member function
Quote:
Originally Posted by JohnW@Wessex
What is it about std::list that makes it special?
If the assign function changes on iterator_category then could you specialise on that?
Where Iter_::iterator_category is bidirectional_iterator_tag or random_access_iterator_tag etc.
It is more to do with the iterator_catgory than list per se... the problem is, specialising on iterator_category would then break the assign for raw pointers, but I guess that is easier to fix. I'll have a play with this idea - thanks for the suggestion. :)
Re: Template specialisation of template class member function
Quote:
the problem is, specialising on iterator_category would then break the assign for raw pointers
You could handle all types of iterator (including pointers) by using std::iterator_traits<Iter_>::iterator_category
Re: Template specialisation of template class member function
Quote:
Originally Posted by JohnW@Wessex
You could handle all types of iterator (including pointers) by using std::iterator_traits<Iter_>::iterator_category
I realised that when I was looking at the specialisation. :) I now have a solution...
Re: Template specialisation of template class member function
Ok, it's a bit convoluted but it works. If you think any of it is a bad idea, or could be done in a better way then let me know. :)
I defined a helper class:
Code:
template <typename IteratorCategory_, typename Buffer_>
class AssignmentHelper
{
public:
template <typename Iter_>
void assign(Iter_ first, Iter_ last, Buffer_& buffer)
{
buffer.assignUsingIteration(first, last);
}
};
which I partially specialised as follows:
Code:
template <typename Buffer_>
class AssignmentHelper<std::random_access_iterator_tag, Buffer_>
{
public:
template <typename Iter_>
void assign(Iter_ first, Iter_ last, Buffer_& buffer)
{
buffer.assignUsingMemcpy(first, last);
}
};
I then created a function to test the value_type of my BufferClass:
Code:
//A minor modification of how Andrei Alexandrescu achieves
//primative data type recognition in his book "Modern C++ Design"
template<typename T>
bool isPrimitive(T)
{
typedef char Small;
typedef char (&Big)[2];
Small Test(long double);
Big Test(...);
return sizeof( Test(T()) ) == sizeof(Small) ;
}
Finally, I redefined my BufferClass as follows:
Code:
template <typename T>
class BufferClass
{
public:
typedef T value_type;
template <typename Iter_>
void assign(Iter_ first, Iter_ last)
{
AssignmentHelper<typename std::iterator_traits<Iter_>::iterator_category, BufferClass<T> > assignHelper;
assignHelper.assign(first, last, *this);
}
template <typename Iter_>
void assignUsingMemcpy(Iter_ first, Iter_ last)
{
if(!isPrimitive(value_type()))
{
std::cout << "Buffer<T> value_type is non-POD: ";
assignUsingIteration(first, last);
}
else
{
std::cout << "Can use memcpy" << std::endl;
}
}
template <typename Iter_>
void assignUsingIteration(Iter_ first, Iter_ last)
{
std::cout << "Can't use memcpy" << std::endl;
}
//...
private:
//...
};
Now, when I run it with:
Code:
int main()
{
std::vector<double> vec;
std::list<double> lst;
BufferClass<double> test;
std::cout << "Test with std::list:\n -> ";
test.assign(lst.begin(),lst.end());
std::cout << "Test with std::vector:\n -> ";
test.assign(vec.begin(),vec.end());
std::vector< std::vector<double> > vecNonPod;
BufferClass<std::vector<double> > nonPodTest;
std::cout << "Test with std::vector with non-POD value_type:\n -> ";
nonPodTest.assign(vecNonPod.begin(),vecNonPod.end());
}
I get the following heart warming output:
Code:
Test with std::list:
-> Can't use memcpy
Test with std::vector:
-> Can use memcpy
Test with std::vector with non-POD value_type:
-> Buffer<T> value_type is non-POD: Can't use memcpy
I would appreciate any feedback.
Re: Template specialisation of template class member function
I thought at first that the helper functions could be specialised directly.
A bit of experimentation showed that partial function template specialisation is not legal C++. :(
Re: Template specialisation of template class member function
That point gave me a real headache when attempting to come up with a solution. In the end, I had to make the specialisation at the class level. :(
The funny thing is, although it is illegal to specialise a member function without fully specialising the enclosing class, and it is illegal to fully specialise a nested class without fully specialising the enclosing class, it is not illegal to partially specialise a nested class even if the enclosing class is not fully specialised.
With that thought, I think I'll nest the AssigmentHelper class and its partial specialisation within the buffer and make its definition private. :)
Re: Template specialisation of template class member function
You may want to check out boost::type_traits for doing this sort of thing.
It is now part of TR1. for example
You can also look at the source code of an STL implementation like STLport to see boost::type_traits in use to do this sort of optimization.
Re: Template specialisation of template class member function
Thanks souldog, but unfortunately boost is not an option, so I was trying to figure out how to do it myself.
Re: Template specialisation of template class member function
No idea what is talking here.
What is tag and what is benefits code in this way rather than create different assign function in a class ?
Thanks for your help.