I am working with a class that uses STL containers as a template parameter. Not all containers provide the same methods though, so I am trying to figure out how I can specialise specific methods based on the container used.
Example:
template<typename container>
class A
{
private:
container m_container;
public:
void foo(); // does something container specific
// more generic methods that work with any container
};
The following code doexsn't compile saying "Can't match method specialisation", but this is approximately what I want to achieve:
template<typename T>
template<>
void A<std::vector<T> >::foo()
{
// vector specific implementation
}
template<typename T>
template<>
void A<std::map<T> >::foo()
{
// map specific implementation
}
I have to support a number of compilers including MSVC2010, gcc C++99, an old Solaris compiler...
The only way around this fiasco that I found was to implement external methods that do whatever foo
is supposed to do and overload them for the different container types. But I don't want to expose those functions globally, is there a way to do it through specialisations?
Special case where it's not possible to outsource them is constructor specialisations...
Use tag-dispatching:
template <typename T>
struct tag {};
template <typename container>
class A
{
private:
container m_container;
template <typename T, typename Alloc>
void foo_spec(tag<std::vector<T, Alloc> >)
{
// vector specific implementation
}
template <typename K, typename V, typename C, typename Alloc>
void foo_spec(tag<std::map<K,V,C,Alloc> >)
{
// map specific implementation
}
public:
void foo()
{
foo_spec(tag<container>());
}
// more generic methods that work with any container
};
DEMO 1
Partially-specialize a separate class with a static member function:
template <typename T>
struct Impl;
template <typename T, typename Alloc>
struct Impl<std::vector<T, Alloc> >
{
static void foo_spec()
{
// vector specific implementation
}
};
template <typename K, typename V, typename C, typename Alloc>
struct Impl<std::map<K,V,C,Alloc> >
{
static void foo_spec()
{
// map specific implementation
}
};
template <typename container>
class A
{
private:
container m_container;
public:
void foo()
{
Impl<container>::foo_spec();
}
// more generic methods that work with any container
};
DEMO 2
Derive from a partially specialized class + CRTP idiom:
template <typename container>
class A;
template <typename CRTP>
struct Base;
template <typename T, typename Alloc>
struct Base<A<std::vector<T, Alloc> > >
{
void foo()
{
// vector specific implementation
A<std::vector<T, Alloc> >* that = static_cast<A<std::vector<T, Alloc> >*>(this);
}
};
template <typename K, typename V, typename C, typename Alloc>
struct Base<A<std::map<K,V,C,Alloc> > >
{
void foo()
{
// map specific implementation
A<std::map<K,V,C,Alloc> >* that = static_cast<A<std::map<K,V,C,Alloc> >*>(this);
}
};
template <typename container>
class A : public Base<A<container> >
{
friend struct Base<A<container> >;
private:
container m_container;
public:
// more generic methods that work with any container
};
DEMO 3
Use an inversed inheritance hierarchy as proposed by David Rodríguez - dribeas in the comments:
template <typename container>
class Base
{
private:
container m_container;
public:
// more generic methods that work with any container
};
template <typename container>
class A;
template <typename T, typename Alloc>
class A<std::vector<T, Alloc> > : public Base<std::vector<T, Alloc> >
{
public:
void foo()
{
// vector specific implementation
}
};
template <typename K, typename V, typename C, typename Alloc>
class A<std::map<K,V,C,Alloc> > : public Base<std::map<K,V,C,Alloc> >
{
public:
void foo()
{
// map specific implementation
}
};
DEMO 4
You can't specialize individual methods, but the whole class template:
template<typename container>
class A
{
...
...
template<typename T>
class A<vector<T>>
{
If you want most methods to be common and only some methods different, you can inherit all of the specializations from a common base class.
template<typename container>
class A : public ABase<container>
{
...
...
template<typename T>
class A<vector<T>> : public ABase<vector<T>>
{
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With