Template Specialization

Template specialization is useful but sometimes hard to master. Today I bumped into a situation I did not fully understand before but managed to resolve after all. I’d like to share some experiences here:

So the problem starts with explicit specialization of a class method. Suppose I have the code:

Service.h


class Service{
public:
  template<typename T> T returnVal() const;
};

I want to specialize returnVal() so that if T = void, it does not do anything. But per C++ standard, member template methods can not be declared within the class.

Solution 1: So you would write the specialization after the class definition:

template<typename T>
T Service::returnVal() const{
  T val;
  Util::getValue( val );
  return val;
};
template<>
void Service::returnVal() const{ return; }

However, this is not going to work. gcc compiles the code. But suppose the ServiceClass is a parent class of Service1, Service2… where they are declared in Service1.cc, Service2.cc,..., and compiled separated as Service1.o, Service2.o,... and the executable is linked against Service1.cc, Service2.cc, the linker would complain it finds multiple definitions of the same symbol, because it finds the same template member method in each of the object file.

Solution 2: Move the template methods into a Service.cc

and link Service.o, Service1.o, Service2.o... together. Again, gcc compiles the code, but linker instead complains the template methods are not found.

Solution 3: Use a template delegate function

This solution is proposed on StackOverflow

template<typename T> T delegate_returnVal(){ ... }
template<> void delegate_returnVal(){ ... }

class Service{
public:
  template<typename T> T returnVal() const{
    return delegate_returnVal<T>();
  }
};

Again, similar to solution 1 and 2, the linker either complains multiple identical symbols found or symbols not found.

Solution 4: Use a template delegate class.

This is the solution I end up with.

template<typename T>
struct Delegator{
  T getVal(){
    T val;
    Util::getValue( val );
    return val;
  }
};

template<>
struct Delegator<void>{
  void getVal() {return;}
};

class Service{
public:
  template<typename T> T returnVal() const{
    Delegator<T> d();
    return d.getVal();
  }
};

Feel free to leave any thoughts or comments!

Leave a Reply 請留下你的回應