Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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

Write the specialization outside the class definition:

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

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

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.

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.

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 */
            };
    };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top