2

How to reduce code duplication of a class that is template specialized?

I am trying to create a class (MyArray) that acts like std::vector but receives raw-pointer as parameter in some functions.

Here is a simplified version of it :-

template<class T> class MyArray{
    T database[10];
    public: T& get(int index){return database[index];}
    void set(int index, T t){
        database[index]=t;
    }
};
template<class T> class MyArray<std::unique_ptr<T>>{
    T* database[10];
    public: T*& get(int index){return database[index];}
    void set(int index, std::unique_ptr<T> t){
        T* tmp=t.release();
        database[index]=tmp;  
    }
};

Here is a test:-

class B{};
int main() {
    MyArray<B>   test1;
    MyArray<B*>  test2;
    MyArray<std::unique_ptr<B>> test3;
    test3.set(2,std::make_unique<B>()));
    return 0;
}

Question: Please demonstrate an elegant way to reduce the above code duplication in MyArray.

A solution that I wished for may look like :-

template<class T> class MyArray{
    using U = if(T=std::uniquePtr<X>){X*}else{T};
    U database[10];
    public: U& get(int index){return database[index];}
    void set(int index, T t){
        U u = convert(t);//<-- some special function
        database[index]=u;
    }
};

There might be some memory leak / corruption. For simplicity, please overlook it.
I just want an idea/rough guide. (no need to provide a full run-able code, but I don't mind)

In real life, there are 20+ function in MyArray and I wish to do the same refactoring for many classes.

Edit: I have (minor) edited some code and tag. Thank AndyG and Jarod42.

javaLover
  • 6,347
  • 2
  • 22
  • 67

2 Answers2

3

Maybe can you delegate the implementation details to a struct you provide to your class, and you specialize this struct, not MyArray:

template <typename T>
struct Policy {
  using type = T;
  static type convert(T t) { ... }
};

template <typename T>
struct Policy<std::unique_ptr<T>> {
  using type = T*;
  static type convert(T t) { ... }
};

template <typename T, typename P = Policy<T>>
class MyArray
{
  using type = typename P::type;

  void set(int index, T t) { type result = P::convert(t); }
};
piwi
  • 5,136
  • 2
  • 24
  • 48
1

You might think about using a common base class for the common functionality:

template<class T>
class Base{
    protected:
    T database[10];
    public:
    T& get(int index){return database[index];} 
};

template<class T> 
class MyArray : public Base<T>{
    public:
    void set(int index, T t){
        this->database[index]=t;
    }
};

template<class T> 
class MyArray<std::unique_ptr<T>> : public Base<T*>
{
    public:
    void set(int index, std::unique_ptr<T>&& t){
        T* tmp=t.release();
        this->database[index]=tmp;   //a little different
    }
};

Demo

AndyG
  • 39,700
  • 8
  • 109
  • 143