6

Say I have this:

template<typename T, int X>
class foo 
{
public:
  void set(const T &t);
};

template<typename T, int X>
void foo::set<T, X>(const T &t)
{
  int s = X;
  // ...etc
}

Could I specialize the function type 'T' but leave 'X' as a template parameter?

class bar;

template<int X>
void foo::set<bar, X>(const bar &t)
{
  int s = X;
  // ...etc
}

Is this possible?

MarkP
  • 4,168
  • 10
  • 43
  • 84

4 Answers4

7

This is surprisingly easy once you get the hang of it

template<typename T, int X>
class foo 
{
private:
  template<typename, int> class params { };

public:
  void set(const T &t) {
    set(t, params<T, X>());
  }

private:
  template<typename T1, int X1>
  void set(const T1 &t, params<T1, X1>) {
     // ...
  }

  template<int X1>
  void set(const bar &t, params<bar, X1>) {
    // ...
  }
};

This is necessary because if you explicitly specialize a single member, you must provide all template arguments. You cannot leave some off.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • That is correct but I personally would avoid such tricks. It makes the code unreadable. IMO partial specialization of the class or something similar depending on the situation (e.g. creating base class template and partially specializing it and implementing (many?) non-specialized functions in non-specialized derived class) is much better decision. – Serge Dundich Oct 04 '11 at 06:19
  • @Serge partial specialization specializes the whole class. So it's unsuitable if he only wants special behavior for a single function. creating a base template is much more noise and inconvenience (you won't have access to members of "foo", ...). If you have a cleaner solution to the above, I welcome you to post it. – Johannes Schaub - litb Oct 04 '11 at 11:00
  • "partial specialization specializes the whole class" - True. "creating a base template is much more noise and inconvenience" - Usually it is not inconvenience - it is a minor additional work to make the architecture consistent. If there is a need for specialization then typically there is some special logic about this case that might deserve separate (base) class specialization. If there are lots of common member objects then no problem to put them (protected) in another class to be the base for both parent specializations (and usually there is a logic behind this). – Serge Dundich Oct 04 '11 at 21:50
  • I know it sounds complicated but if everything is implemented consistently then it is much more readable than overloading tricks. – Serge Dundich Oct 04 '11 at 21:52
  • @Serge I don't understand why you think that these two overloads are unreadable. IMO, they are the most readable solution. – Johannes Schaub - litb Oct 05 '11 at 04:47
3

You could consider rewriting your code to make the member function a separate template:

template <int X> class foo
{
  template <typename T> void set(const T &);
  // ...
};

Then you can provide explicit specializations for the template foo<X>::set.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2

No. That is not allowed. A class member function must be fully specialized. For example, it should be,

template<>
void foo<bar, 5>::set(const bar &t)
{          //^^^^
  int s = 5;
  // ...etc
}
iammilind
  • 68,093
  • 33
  • 169
  • 336
1

You can partially specialize the whole class. In this case you can give different implementations to the set function for every specialization of the class.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212