yotamoo
yotamoo

Reputation: 5462

templates function specialization, c++

I am practicing function specialization, and I was trying to create a little storage object with a specialized print function. Here's my code:

#ifndef STORAGE_HPP_
#define STORAGE_HPP_

#include <iostream>

using namespace std;

template <typename T, int size> class Storage
{ //LINE 16 ERROR
public:
    Storage():arr(new T*[size]){};
    ~Storage()
    {
        for (int i = 0; i < size; i++)
        {
            delete arr[i];
        }
        delete[] arr;
    }
    void push(T obj, int i)
    {
        arr[i] = new T(obj);
    }
    void print()
    {
        for (int i = 0; i < size; i++)
        {
            cout << *arr[i];
        }
        cout << endl;
    }


private:
    T** arr;
};

template <typename T, int size> void Storage<int,size>::print() //LINE 38 ERROR
{
    for (int i = 0; i < size; i++)
        {
            cout << (char) *arr[i];
        }
        cout << endl;
}
#endif /* STORAGE_HPP_ */

And I get this error:

../Storage.hpp:38:63: error: invalid use of incomplete type
class Storage<int, size>
../Storage.hpp:9:1: error: declaration of ‘class Storage<int, size>’

So, first question: can specialized functions be implemented inside a class? I tried but got an error. Second, why do I get the error I've attached? Thanks!

EDIT: I tried something new as someone here suggested. I've change print inside the class to be only void print() and I've implemented it outside so I can overload the function. Here:

template <typename T, int size>
void Storage<T,size>::print()
{
    for (int i = 0; i < size; i++)
    {
        cout << *arr[i];
    }
    cout << endl;
}


template <typename T, int size>
void Storage<int,size>::print() //ERROR HERE
{
        for (int i = 0; i < size; i++)
        {
            cout << *arr[i];
        }
        cout << endl;
}

Now I get invalid use of incomplete type ‘class Storage<int, size>’Where I wrote ERROR HERE (obviously!) I understand that's a common solution, am I right? And why do I get this error?

Upvotes: 0

Views: 1003

Answers (4)

Frigo
Frigo

Reputation: 1723

The only error I can see is an extraneous typename T in your specialization. It should be:

template <int size> void Storage<int,size>::print() {...}

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 477600

The problem is that you are trying to use a partial specialization of the entire class without having defined the partially-specialized class.

If print were itself a function template, the situation would be different, because you can indeed specialize function templates. However, your construction only has the entire class as a template.

This means that template <typename T, int n> class Storage<T, n> and template <int n> class Storage<int, n> are entirely different, unrelated classes. Thus you must first define the latter class:

template<int n> class Storage<int, n>
{
  // define everything
};

template<int n> void Storage<int, n>::print() { /* implement */ }

Consider that the partial specialization Storage<int, n> may be an entirely different class from the primary template, and it may have totally different member functions. The compiler has no way of knowing this until you actually define that class.


Following sbi's comment, here's one idea:

//... in the class definition

template<typename S, int m> friend void print_helper(const Storage<S, m> &);
template<int m> friend void print_helper(const Storage<int, m> &);

void print() { print_helper(*this); }

// outside:

template <typename S, int size> void print_helper(const Storage<S, size> & s)
{
  // ...
}
template <int size> void print_helper(const Storage<int, size> & s)
{
  // ...
}

Instead of the friend you could also make the helper function template static, but that might add a lot of code bloat, since you'll have two static function templates per class type, rather than just two globally.

Upvotes: 3

Michael J
Michael J

Reputation: 7949

I don't think you can use partial specialisation on a single method. You can only use full specialisation.

The question is: why do you want to use an array with a specified size? Why not just use an std::vector and let the push() function size it dynamically (with std::vector::push_back() )?

Upvotes: 0

PlasmaHH
PlasmaHH

Reputation: 16046

Partial specializations always need to use the complete template, since they define a template too.

So this would not work:

template <int size> void Storage<int,size>::print()

Full specializations of member functions can be done out of line for single member functions, because they define functions.

So this would work:

template <> void Storage<int,44>::print() 

And you can not declare/define any (partial) specializations within the primary template.

Upvotes: 0

Related Questions