【问题标题】:C++ specialize template class function without duplicating codeC++ 专门模板类功能,无需重复代码
【发布时间】:2014-08-04 13:08:02
【问题描述】:

我想写 5 个不同的类,每个类都有许多完全相同的成员函数,除了一个,它对每个类都是特殊的。我可以写这个避免代码重复吗?

问候, 阿列克谢斯

下面是我的代码的一个非常简短的版本,它会引发错误:

template_test.cpp:15:35: error: invalid use of incomplete type ‘class impl_prototype<cl, 1>

#include <iostream>
using namespace std;

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 cl + 1 * x;}

};

template <int cl>
int impl_prototype<cl, 1>::g(int x) { return cl + 3 * 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;
}

【问题讨论】:

  • 它们可以有一个共同的基类吗?
  • 继承和虚函数怎么样?
  • @JoachimPileborg 继承 + 帮助器的部分特化更惯用,在 OP 的代码中看不到 virtual
  • 这是this的完全相同的副本

标签: c++ function class templates partial-specialization


【解决方案1】:

类模板的成员函数可以显式特化,但不能部分特化。

只需创建一个可以部分特化的辅助函数对象:

#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; }    
};

然后调用那个助手(临时函数对象将被优化掉):

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

【讨论】:

  • 作为继承的替代方案,我们可以转发给助手:int g(int x) { return g_impl&lt;cl, dim&gt;().g(x); }
  • @Jarod42 制作了一个可以部分特化并从g() 调用的函数对象。感谢您的评论。
  • @Walter 只是把它变成了一个部分特化的函数对象。
  • @Walter:如果需要,您可以向辅助类方法提供额外信息。
【解决方案2】:

另一种方法是标签调度,类似于:

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>());}
};

【讨论】:

    【解决方案3】:

    您有多种选择。

    1. 使用继承,您可以专门化基类模板并仅使用派生类模板添加大量其他相同的成员函数。

    2. 声明一个辅助类(函数对象),该类是部分专用的并从impl_prototype&lt;&gt;::g() 调用。这与1.非常相似,但避免了继承(例如,参见TemplateRex的答案);

    3. 使用 SFINAE 来“专门化”成员函数:

      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); }    
      };
      

    我经常使用最后一种方法,因为它避免了所有继承问题(特别是在非平凡构造函数的情况下)和类外的任何辅助对象。

    在您的特定示例中,一个更简单的可能性是

    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); }   
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-05
      • 2014-05-13
      • 2012-01-21
      • 2013-04-09
      • 1970-01-01
      • 1970-01-01
      • 2022-12-13
      • 1970-01-01
      相关资源
      最近更新 更多