EFred
EFred

Reputation: 29

C++ pointer template specialization

I'm trying to design a template class of type T* which is declared as follows:

template <class T>
class StructParamPublic<T*>
    {
    .....
    protected:
    T* m_pData;
    };

which can be used for creating a struct like this

StructParamPublic <FloatArrayStruct*> m_pFloatArray;

where

FloatArrayStruct
{
float* pData;
size_t arraySize;
};

However, when I compile this I'm getting an error that says StructParamPublic is not a template type.

If I define the following template class

template <class T>
class StructParamPublic
    {
    .....
    protected:
    T m_Data;
    };

then this error goes away. For some design consideration I don't want to add the second definition to the framework.

My solution was to come up with something like this

template <class T>
class StructParamPublic
    {
    .....
    protected:
    T* m_pData;
    };

and it compiled fine.

So my question: Is template <class T> class StructParamPublic some kind of 'base template class' and template <class T>class StructParamPublic<T*> some sort of derivation of that class?

Upvotes: 0

Views: 1451

Answers (3)

Chris Beck
Chris Beck

Reputation: 16224

You could do it like this:

template<typename T>
class StructParamPublic;
// ^ This just "forward declares" the class for all possible template values

template<typename U>
class StructParamPublic<U*> {
    ...
};
// ^ This is a partial specialization of the above class template. It will deduce the type of T from the pointer type that you instantiate the template with

If you do it that way then the syntax StructParamPublic<int*> will be legal and it will deduce the type T as int in the template when you use it.

In general when you have template<typename T> class < T::dependent_type > { ... }; you should use a template specialization for it to work the way you expect, and that requires that you make the "primary" template first which is not specialized, even if that primary template doesn't actually do anything (besides make a declaration).

Note also that you don't actually need to use type traits here to enforce the pointer type requirement. In the above code if you try to use it with a non-pointer type, it will just find the primary template only and not find a real definition. If you wanted you could add a static assert in the primary template "missing * in StructParamPublic<...>" or similar.

Upvotes: 1

Jarod42
Jarod42

Reputation: 218323

template <class T> class StructParamPublic<T*>;

is a specialization of

template <class T> class StructParamPublic;

So for your problem, you have several possibilities:

  • (partial) specialization

    template <class T> class StructParamPublic;
    
    template <class T>
    class StructParamPublic<T*>
    {
    // code
    protected:
        T* m_pData;
    };
    

    StructParamPublic<int> would lead to an error of undefined class.

  • or static_assert

    template <class T>
    class StructParamPublic
    {
        static_assert(std::is_pointer<T>::type, "type should be a pointer type");
        using value_type = typename std::remove_pointer<T>::type;
    
    // code
    protected:
        T m_pData; // or value_type* m_pData;
    };
    

    StructParamPublic<int> would lead to an clean error thanks to static_assert.

  • or change meaning of your parameter as your solution.

    template <class T>
    class StructParamPublic
    {
        .....
    protected:
        T* m_pData;
    };
    

    StructParamPublic<int> is used here whereas previous solution requires StructParamPublic<int*>.

Upvotes: 1

R Sahu
R Sahu

Reputation: 206737

You don't need to define the second class template. You can just use a forward declaration.

template <class T> class StructParamPublic;

and then you can use

template <class T>
class StructParamPublic<T*>
    {
    .....
    protected:
    T* m_pData;
    };

Upvotes: 1

Related Questions