简体   繁体   中英

How to specialize template member function for another template class?

I am trying to make specialized member functions in the heap class for only DijkstraState class but when I compile and run I get errors I don't know if I am specializing addElement, reheapdown, siftup in a wrong way

This is my code

#ifndef HEAP_H
#define HEAP_H

#include "DijkstraState.h"
template <class T> class Heap
{
private:
    T* container; //Points to the array in which heap is implemented
    int counter; //Number of full places
public:
    Heap(int size=100)
    {
        container = new T[size]; 
        counter = 0; 
    }
    ~Heap()
    {
        delete[] container;
    }
    bool isEmpty()
    {
        return (counter == 0) ;
    }
    void reHeapDown(int i);
    void siftUp(int i);
    void addElement(T x);
    T& removeMin();
    T& getMin();
};


template <class T> void Heap<T>::siftUp(int i)
{
    while(true)
    {
        int parent = (i-1)/2 ;
        if(parent < 0 )
        {
            break ;
        }

        if(container[i] < container[parent]) //element is smaller than its parent then swap
        {
            T temp = container[parent] ;
            container[parent] = container[i] ;
            container[i] = temp ;
            i = parent ;
            //set the index of the parent
        }
        else
        {
            break ;
        }
    }
}

template <>
void Heap<DijkstraState<class T>>::siftUp(int i)
{
   while(true)
    {
        int parent = (i-1)/2 ;
        if(parent < 0 )
        {
            break ;
        }

        if(container[i] < container[parent]) //element is smaller than its parent then swap
        {
            DijkstraState<T> temp = container[parent] ;
            temp.setIndex(i) ;
            container[parent] = container[i] ;
            container[parent].setIndex(parent) ;
            container[i] = temp ;
            i = parent ;
            //set the index of the parent
        }
        else
        {
            break ;
        }
    }
}

template <class T> void Heap<T>::reHeapDown(int i)
{
    int smallestChild;
    while(true)
    {
        int child1 = (2*i) + 1 ;
        int child2 = (2*i) + 2 ;

        if(child1 >= counter) // an element with no children
        {
            break;
        }

        if(child2 >= counter) //element has only one child
        {
            smallestChild = child1 ;
        }
        else if(container[child1] <= container[child2]) //first child is smaller than or equal second child
        {
            smallestChild = child1 ;
        }
        else
        {
            smallestChild = child2 ;
        }

        if(container[i] < container[smallestChild]) //parent is greater than or equal smallest child.
        {
            break ;
        }

        T temp = container[smallestChild] ;
        container[smallestChild] = container[i] ;
        container[i] = temp ;
        i = smallestChild ;
        //set the index of the child and parent
    }
}

template <>
void Heap<DijkstraState<class T>>::reHeapDown(int i)
{
    int smallestChild;
    while(true)
    {
        int child1 = (2*i) + 1 ;
        int child2 = (2*i) + 2 ;

        if(child1 >= counter) // an element with no children
        {
            break;
        }

        if(child2 >= counter) //element has only one child
        {
            smallestChild = child1 ;
        }
        else if(container[child1] <= container[child2]) //first child is smaller than or equal second child
        {
            smallestChild = child1 ;
        }
        else
        {
            smallestChild = child2 ;
        }

        if(container[i] < container[smallestChild]) //parent is greater than or equal smallest child.
        {
            break ;
        }

        DijkstraState<T> temp = container[smallestChild] ;
        temp.setIndex(i) ;
        container[smallestChild] = container[i] ;
        container[smallestChild].setIndex(smallestChild) ;
        container[i] = temp ;
        i = smallestChild ;
        //set the index of the child and parent
    }
}


template <class T> void Heap<T>::addElement(T x)
{
    container[counter] = x ; //put the element in the last place in the array
    int i = counter ; //index of the added element
    counter++ ; //increase number of occupied places

    if(counter == 1) //special case: empty heap
    {
        //set index of the newly added element
        return;
    }

    siftUp(i);
}

template <>
void Heap<DijkstraState <class T>>::addElement(DijkstraState<T> x)
{
    container[counter] = x ; //put the element in the last place in the array
    int i = counter ; //index of the added element
    container[counter].setIndex(i);
    counter++ ; //increase number of occupied places

    if(counter == 1) //special case: empty heap
    {
        //set index of the newly added element
        return;
    }

    siftUp(i);
}


template <class T> T& Heap<T>::removeMin()
{
    if(isEmpty())
    {
        return -1;  
    }
    else
    {
        T min = container [0] ; //get the first element
        container[0] = container[--counter] ; //set the last element to the first element and decrease counter by one 

        reHeapDown(0) ;

        return min ;
    }
}

template <class T> T& Heap<T>::getMin()
{
    return container[0];
}

#endif

These are the errors generated

1>  main.cpp
DijkstraState.h(12): error C2079: 'DijkstraState<T>::d' uses undefined class 'T'
 with
1>          [
1>              T=T
1>          ]
1>          c:\users\fakhr el din\documents\visual studio 2010\projects\dijkstra's_algorithm\dijkstra's_algorithm\Heap.h(68) : see reference to class template instantiation 'DijkstraState<T>' being compiled
1>          with
1>          [
1>              T=T
1>          ]

Your problem is that the class is templated (ie, the member function isn't) therefore you cannot specialize the function you would need to special the class. However, you may be able to configure it such that the member function is implemented in terms of a templated function (or other similar techniques, which would allow you to specialize a subset of the implementation), at which point you could fully specialize or overload the function. The following code may not be what you need but illustrates the point. It uses a standalone function and a private nested class (which could be instantiated with the class state to be modified).

Example Code

#include <iostream>

template<typename T>
void bar()
{
    std::cout << "general Foo::bar()\n";
}

template<>
void bar<int>()
{
    std::cout << "specialized Foo::bar()\n";
}

template<typename U>
struct Bar2Impl
{
    static void bar2() { std::cout << "general Foo::bar2()\n"; }
};

template<>
struct Bar2Impl<int>
{
    static void bar2() { std::cout << "specialized Foo::bar2()\n"; }
};

template<typename T>
class Foo
{
private:

public:
    void bar() { ::bar<T>(); }

    void bar2() { Bar2Impl<T>::bar2(); }
};

int main()
{
    Foo<double> f1;
    f1.bar();
    f1.bar2();

    Foo<int> f2;
    f2.bar();
    f2.bar2();

    return 0;
}

Example Output

general Foo::bar()
general Foo::bar2()
specialized Foo::bar()
specialized Foo::bar2()

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