Search code examples
c++templatestemplate-meta-programming

How do I add a template specialization when for a generic method on a generic class when the two types are equal?


I'm trying to add in a specialization where the generic type of method and class agree, but I haven't been able to figure out exactly how to specify the template instantiation (if it is even possible).

My best guess would be something like the following (though it obviously doesn't compile):

template<typename ClassT>
class Foo
{
public:
  ClassT x;

  template<typename MethodT>
  void Bar(MethodT arg)
  {
  }
};

template<typename T>
template<>
void Foo<T>::Bar(T arg)
{
  x = arg;
}

Solution

  • As is usually the case when considering function template specialization, an overload can handle it:

    template<typename MethodT>
    void Bar(MethodT arg)
    {
    }
    
    void Bar(ClassT arg)
    {
      x = arg;
    }
    

    When you call Bar, one of the candidates will be a function template specialization and one won't. Think of the class template as stamping out real, concrete member functions where possible when it's instantiated. There's a rule pretty late in overload resolution to prefer the one that isn't a function template specialization if it's a tie up to that point.

    What you end up with is the second overload being called when there's an "exact match" in types (which allows for a difference in top-level const). If exact matches are too narrow, you can restrict the first overload to widen the second:

    // Allow the other overload to win in cases like Foo<int>{}.Bar(0.0).
    // std::enable_if works as well before C++20.
    template<typename MethodT>
    void Bar(MethodT arg) requires (not std::convertible_to<MethodT, ClassT>)
    {
    }