C++ specialize template class function without duplicating code

二次信任 提交于 2019-12-05 13:54:18

Member functions of class templates can be explicitly specialized but not partially specialized.

Just make a helper function object that you can partially specialize:

#include <iostream>
using namespace std;

template<int cl, int dim>
struct g_impl
{
  int operator()(int x) { return cl + 1 * x;}    
};

template<int cl>
struct g_impl<cl, 1>
{
  int operator()(int x) { return cl + 3 * x; }    
};

and then call that helper (the tempoary function object will optimized away):

template <int cl, int dim>
class impl_prototype 
{
public:
  impl_prototype() {}

  int f(int x) { return cl + 2 * g(x); }
  int g(int x) { return g_impl<cl, dim>()(x); }
};

int main ()
{
  impl_prototype<0, 0> test_0;
  impl_prototype<0, 1> test_1;


  cout << test_0.f(5) << " " << test_0.g(5) << std::endl;
  cout << test_1.f(5) << " " << test_1.g(5) << std::endl;


  return 0;
}

Live Example

An other method is Tag dispatching, something like:

template <int cl, int dim>
class impl_prototype
{
    int g(int x, std::integral_constant<int, 1>) { return cl + 3 * x; }

    template <int I>
    int g(int x, std::integral_constant<int, I>) { return cl + 1 * x; }

public:
    int f(int x) { return cl + 2 * g(x); }
    int g(int x) { return g(x, std::integral_constant<int, dim>());}
};

You have several options.

  1. use inheritance, where you specialise the base class template and add the multitude of other identical member functions only with the derived class templates.

  2. declare a helper class (function object) that is partially specialised and called from impl_prototype<>::g(). This is very similar to 1., but avoids inheritance (for an example, see the answer by TemplateRex);

  3. use SFINAE to "specialise" the member function:

    template<int cl, int dim>
    class impl_prototype
    {
      template<bool dim_equals_one> typename std::enable_if<!dim_equals_one,int>::type
      _g(const int x) const { return cl+1*x; }
      template<bool dim_equals_one> typename std::enable_if< dim_equals_one,int>::type
      _g(const int x) const { return cl+3*x; }
    public:
      int f(const int x) const { return cl+2*g(x); }
      int g(const int x) const { return _g<dim==1>(x); }    
    };
    

I often use this last approach as it avoids all the issues of inheritance (in particular in the case of non-trivial constructors) and any helper objects outside the class.

In your particular example, a much simpler possibility is

template<int cl, int dim>
class impl_prototype
{
public:
  int f(const int x) const { return cl + 2 * g(x); }
  int g(const int x) const { return cl + (dim==1? 3*x : x); }   
};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!