1

I think I'm just missing something small. I want to specialize the constructor of a templated class for an implementation where T = the template class with any parameter. Sorry if my vocab is a bit off. Basically, I need to allow for jagged 2D arrays, so I might have a ArEl<ArEl<int>> and I would like to preinitialise all the array lengths.

using namespace std;

template <typename T>
class ArEl {
 public:
  ArEl(size_t size = 0)
      : rSize(size), rArray(rSize ? new T[rSize]() : nullptr) {}
  ArEl(const ArEl& other);
  virtual ~ArEl() { delete[] rArray; }
  void swap(ArEl& first, ArEl& second);
  void redim(size_t size);

 private:
  std::size_t rSize;
  T* rArray;
};

template <typename T, typename T1>
class ArEl<ArEl<T>> : public ArEl<T1>{
  ArEl(size_t size = 0);
};

EDIT:

I'm getting this error:

error: template parameters not deducible in partial specialization:
 class ArEl<ArEl<T>> : public ArEl<T1>{

3 Answers3

4

You're specializing your object in the wrong way.

template<typename T, typename T1> implies that there's two datatypes that need to be provided, but it's clear that the only thing your template specialization needs is the datatype of the underlying array(s). If the expectation is that ArEl<ArEl<T>> be specialized, it shouldn't take more than this:

template<typename T>
class ArEl<ArEl<T>> {
    /*Blah Blah Blah*/
};

There's no need for inheritance, and no need for a second datatype.

However, I'll also add: there's not really any need for this specialization in the first place. If you don't write the specialization at all, the following code should still work as-is:

ArEl<ArEl<int>> dim2Array(50);
//I'm assuming ArEl will have a member size() function
for(size_t index = 0; index < dim2Array.size(); index++) {
    //I'm assuming ArEl will have an operator[] overload
    dim2Array[index].redim(30);
}
//dim2Array is now 50 int arrays, each of size 30.

I'm assuming that the functionality you're intending is to have something like the following, which does require template specialization like what I posted above:

ArEl<ArEl<int>> dim2Array(50, 30);
//dim2Array is now 50 int arrays, each of size 30.

But if I were you, I'd leave the implementation of ArEl alone and instead invest in writing a Matrix<T> class (or possibly Matrix<T, N>, for N-dimensions) that handles this kind of syntax instead (which you could build using ArEl<T> as the building blocks, incidentally), especially because I don't think you're committed to writing the specializations for ArEl<ArEl<ArEl<int>>> or deeper (and yes, the way you're trying to do it, each level would need its own specialization).

Xirema
  • 19,889
  • 4
  • 32
  • 68
3

Specializing an entire class implies replacing all the members with the ones provided by the specialization. You don't want that.

One option would be to provide all the members that need specialization in a base class: BaseForA<T> would be specialized, and A<T> would derive from it.

Another one would be to use tag dispatching, here's an example of how you can use it to do different actions depending on the type parameter.

#include <iostream>
#include <type_traits>

template<typename T>
struct tag {};

template<typename T>
struct A
{
private:
    template<typename U>
    A(std::size_t s, tag<A<U>>)
    {
        std::cout << "special constructor " << s << "\n";
    }

    A(std::size_t s, ...)
    {
        std::cout << "general constructor " << s << "\n";
    }
public:
    A(std::size_t s = 0) :
        A(s, tag<T>())
    {

    }
};

int main() 
{
    A<int> a;
    A<A<int>> b;
    A<A<long>> c;
    A<long> d;
}

Live on Coliru

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
0

If I understand you correctly you want the specialised version to inherit the generic version and then add something on top of it. The problem here is that you have a specialised ArEl<ArEl<T>>, you cannot request a generic version of it.

The solution is to make the generic version and the specialised version be different types.

template<typename T, bool D=true>
class ArEl { ...

template<typename T>
class ArEl<ArEl<T>>: 
    public ArEl<ArEl<T>, false> { ...

But now the problem is that ArEl<T, true> and ArEl<T, false> are unrelated and incompatible!

The solution is to introduce a common base class for them.

template<typename T>
class ArElBase {
     ... all functionality of ArEl
};

template<typename T, bool D=true>
class ArEl : public ArElBase<T> { 
   using ArElBase<T>::ArElBase;
   // nothing more
}; 

and then the specialisation, unchanged.

Now you can use ArElBase to pass your objects by pointer or reference, but use ArEl to declare objects themselves.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243