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

拈花ヽ惹草 提交于 2019-12-01 01:28:04

问题


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...


回答1:


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




回答2:


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>>
{


来源:https://stackoverflow.com/questions/27444624/how-to-simulate-a-partial-specialization-of-selected-member-functions-based-on-a

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