Can't get method template to specialize properly

284 views Asked by At

I have a template class that otherwise works perfectly, except I need to overload the insert method in case type T is a string.

template <class T> 
class hashtable{
 public:
    void insert(T item){
        /* Do Stuff */          
        };
    template<> void insert(string item){
        /* Do different stuff */
        };
}

This is throwing error C2912: explicit specialization; 'void hashtable::insert(std::string)' is not a specialization of a function template.

I'm not sure what I'm doing wrong, or how I can fix this. All I need is a way to call the insert function differently depending on if T is a string or not.

6

There are 6 answers

0
Michael Simbirsky On BEST ANSWER

You do not need to add the template word at all. You just overload the template function.

class hashtable{
 public:
    template <typename T>
    void insert(T item){
        /* Do Stuff */          
    };

    void insert(string item){
        /* Do different stuff.
        Implementation can go to *.cpp file if necessary. 
        */
    };
};

Beware, though, regardless of the design you can get in trouble when you try to insert the types which are implicitly convertible to std::string, including const std::string & and const char*. Believe it or not, in C++03 std::string had even implicit constructor from int!

That is why people usually prefer to templetize the hashtable class, not the function.

0
Alexis Wilke On

You need to specify the specialization in the template brackets:

template<class string> void insert(string item) ...

The template<> is used when you eliminate all the parameters in a class specialization. There is an example here of such:

http://www.cplusplus.com/doc/tutorial/templates/#template_specialization

3
Kerrek SB On

Write the specialization outside the class definition:

template <typename T> class hashtable { /* ... */ };

template <> void hashtable<std::string>::insert(std::string item)
{
    // ...
}
1
stackmate On

I'm not sure the point of this class. Do you have an internal object within the class of type T? If not, I would just do the following:

class hashtable{
 public:
    template <typename T>
    void insert(T item){
        /* Do Stuff */          
        };

    template<>
    void insert(string item){
        /* Do different stuff */
        };
}

if you do have something of type T within the class then maybe you're looking for this:

template <typename T>
class hashtable{
 public:
    template <typename P>
    void insert(P item){
        /* Do Stuff */          
        };

    template<>
    void insert(string item){
        /* Do different stuff */
        };
}

you need to elaborate a little more on what you're trying to do.

0
htzfun On

Well, maybe it's better to think in another way - you have template data structure, so you should specialize whole structure than just one function - because if you need to specialize another methods for this type(here - for string), you will specialize it in the same class - it will spoil code a bit. My variant of solution is above:

template <class T> 
class hashtable{
 public:
    void insert(T item){
        /* Do Stuff */          
        };
}
template <string> 
class hashtable{
 public:
    void insert(string item){
        /* Do different stuff */          
    };
}

And as edition - you can write hashtable with template hash function - that will remove any specialization. But obviously, you will need to write your own function for string. Example for int and of hashtable:

 template <class T>
 LinearHashFunction {
     int a,b;
     static const int prime = /* some big prime number */
     LinearHashFunction(int a, int b):a(a), b(b) {}
     int operator()(T item) {
         return static_cast<int>(item)*a + b;
     }
 };

 template <class T, class THashFunction> 
 class hashtable{
 private:
    THashFunction<T> hash;
 public:
    void insert(T item){
            /* Do Stuff */
            // get hash:
            int elementsHash = hash(item);          
            };
    template<> void insert(string item){
            /* Do different stuff */
            };
    };
0
Yakk - Adam Nevraumont On

The easiest way to do this is tag dispstching/

Create a traits class that inherits from std::true_type or std::false_type depending on which implementation you want to use.

Then write two impl methods with ture_type and false_type arguments, like this:

 template<typename T> void insert(T&& t) { insert_impl(std::forward<T>(t), traits_test<T>() ); }

template<typename T> void insert_impl(T t, std::true_type descriptive_name ){ code }
template<typename T> void insert_impl(T t, std::false_type another_desc_name ){ code }

by doing this, you avoid needless specialization boilerplate, and make the code easily extensible by just tweaking the traits class.

Method specializations are a bit quirky, even moreso than function template specializations. By using tag dispatching, reasoning about what happens becomes easier in my experience.