I have a template class method
template
T pop();
Now I want to do a template specialization as follows,
Off the top of my head, I usually get around it by using a one-member struct:
template <typename T>
struct pop_impl {
static T pop(classname& x); // normal function
};
template <typename T>
struct pop_impl<std::vector<T>> {
static std::vector<T> pop(classname& x); // specialized for std::vector<T>
};
template <typename T>
T classname::pop() { return pop_impl<T>::pop(*this); }
A possible solution is a non-member function implemented like this
template <class T>
struct classname_pop
{
static T pop(classname &obj) { return obj.pop() ;}
}
template <class T>
struct classname_pop<std::vector<T>>
{
static std::vector<T> pop(classname &obj) {obj.specialized_pop() ;}
}
template <class T>
T classname_pop(classname &obj)
{
return classname_pop_t<T>::pop() ;
}
This answer was originally provided by Austin Salgat in the body of the question Template Specialization for T -> std::vector, (posted under the CC BY-SA 3.0 license), and has been moved here as an answer in order to adhere to the site's Q&A format.
Thanks to Piotr I ended up using tag dispatching. Below is the code for what I ended up doing,
// The public method that is accessed by class.push<std::vector<int>>(12); template<class T> void push(T data) { push(tag<T>(), data); } // The private method that calls the actual vector push for vector types template<class T> void push(tag<std::vector<T>>, std::vector<T> const& data_vector) { push_vector(data_vector); } // The actual implementation template<class T> void push_vector(std::vector<T> const& data_vector) { // Actual implementation in here }
You need a temporary proxy to dispatch to different results:
Example:
#include <algorithm>
#include <iostream>
#include <vector>
class Stack
{
private:
std::vector<int> m_data;
class Pop {
friend class Stack;
public:
Stack& stack;
Pop(Stack& stack)
: stack(stack)
{}
private:
Pop(const Pop&) = default;
Pop& operator = (const Pop&) = default;
public:
operator int () {
std::vector<int>& data = stack.m_data;
int result = -1;
if( ! data.empty()) {
result = data.front();
data.erase(data.begin());
}
return result;
}
operator std::vector<int> () {
std::vector<int>& data = stack.m_data;
std::size_t size = std::min(data.size(), std::size_t(3));
std::vector<int> result(data.begin(), data.begin() + size);
data.erase(data.begin(), data.begin() + size);
return result;
}
};
public:
Stack()
: m_data( {0, 1, 2, 3, 4, 5, 6, 7, 8} )
{}
const std::vector<int>& data() const { return m_data; }
Pop pop() { return Pop(*this); }
};
int main()
{
Stack stack;
int i = stack.pop();
std::vector<int> v = stack.pop();
std::cout << "i = " << i << '\n';
std::cout << "v = {";
for(auto i : v)
std::cout << i;
std::cout << "}\n";
}
Disclaimer: I consider the code totally useless (It might become useful if there is a pop() just returning a single value and a pop(std::size_t) converting to different containers, where the destructor of Pop is doing the erase).