How to simulate a partial specialization of selected member functions based on a template parameter that is an STL container?

瘦欲@ 提交于 2019-12-01 03:58:58
Piotr Skotnicki

Option #1

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

Option #2

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

Option #3

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

Option #4

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>>
{
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!