简体   繁体   中英

partial specialization of function in template class

I have a template class representing an array of numerical values.

I want this class to work for any type of numerical value (eg int, double, etc.) and three types of container (std::vector, std::deque, and std::list).

Here are the relevant bits of the implementation for my specific problem :

template < typename Numeric_t, typename Container = std::vector<Numeric_t> >
class Array {

  // field member
  Container m_data;

  // other stuff here
  // ...

  // random element access for std::vector and std::deque
  Numeric_t & operator[] (unsigned int index) { return m_data[index]; }

  // random element access for std::list
  Numeric_t & operator [] (unsigned int index) {
    std::list<Numeric_t> :: iterator it = m_data.begin();
    std::advance(it, index);
    return *it;
  }

}

Of course, the compiler doesn't allow me to overload the operator [] .

What I would need is a kind of partial specialization for operator [] specific for std::list, but partial template function specialization is not allowed either in C++.

(I know that random element access is not efficient for a list, but that's not the point here).

Ideally, in the client code I would like to use the Array class like this :

Array < int, std::vector<int> > vec;
Array < int, std::list<int> >   lst;

// fill arrays here
// ...

std::cout << vec[0] << std::endl;
std::cout << lst[0] << std::endl;

After lot of research I was not able to find a working solution.

What would be the most elegant way to solve this problem ?

Thanks for your help.

A clean solution is to use full-class template specialization. The different specializations can be derived form one common base class, in order to share common code.

Write a class ArrayBase containing all the code that does not depend on the particular container type and that grants access to the container, by making it protected or making Array a friend class.

template <class Numeric_t, class Container>
class Array
  : public ArrayBase<Numeric_t, Container>
{
  // Container specific code, generic version that works for all containers.
};

template <class Numeric_t>
class Array<Numeric_t, std::vector<Numeric_t>>
  : public ArrayBase<Numeric_t, std::vector<Numeric_t>>
{
  // Optimized code for std::vector.
}

Another approach: You can also write a static member function containing code to access the idx -th entry of the container and specialize that function:

 
 
 
  
  template <class Numeric_t, class Container> class Array { template <class Cont> static Numeric_t get(Cont const& container, unsigned int idx) { std::list<Numeric_t>::iterator it = container.begin(); std::advance(it, idx); return *it; } template <> static Numeric_t get(std::vector<Numeric_t> const& container, unsigned int idx) { return container[idx]; } public: Numeric_t operator[](unsigned int idx) const { return get(m_data, idx); } };
 
  

I am sorry, this does not work. I forgot that you can't specialize static member functions ... again.

Another alternative is to use SFINAE, but it is a non-idiomatic use of it and I would not recommend it in this case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM