【问题标题】:C++ Partial Template Specialization: Member Functions [duplicate]C ++部分模板专业化:成员函数[重复]
【发布时间】:2017-06-06 05:51:37
【问题描述】:

我有一个模板

template <int a, int b>
class MyTemplateClass
{
    // ....
    void computeSomething();
};

我想部分专门研究 b 的两个特殊情况:

template<int a>
void MyTemplateClass<a, 2> :: computeSomething()
{
    // Special case for b=2 here
}


template<int a>
void MyTemplateClass<a, 3> :: computeSomething()
{
    // Special case for b=3 here
}

但是,据我所知,部分特化对成员函数无效。我怎样才能实现我想要的?还有其他解决方案吗?谢谢!

【问题讨论】:

  • 您需要对整个类进行部分特化,或者制作几个处理特定主类特化的重载模板方法。

标签: c++ templates template-specialization


【解决方案1】:

一种可能的方法是提取compute(),仅为它创建一个基类并专门化这个基类。

我的意思是...如果您为 fooSub 创建一个通用版本和两个专业化版本

template <int a, int b>
struct fooSub
 {
   void compute ()
    { std::cout << "- foo generic compute()" << std::endl; }
 };

template <int a>
struct fooSub<a, 2>
 {
   void compute ()
    { std::cout << "- foo compute() for 2" << std::endl; }
 };

template <int a>
struct fooSub<a, 3>
 {
   void compute ()
    { std::cout << "- foo compute() for 3" << std::endl; }
 };

您可以通过继承“专门化”foo 中的计算,如下所示

template <int a, int b>
struct foo : public fooSub<a, b>
 { };

如果您至少可以使用 C++11,另一种可能的解决方案是使用 SFINAE (std::enable_if) 激活/停用不同版本的 compute(),如下面的bar 类中所示

template <int a, int b>
struct bar
 {
   template <int bb = b>
   typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
         compute ()
    { std::cout << "- bar generic compute()" << std::endl; }

   template <int bb = b>
   typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
    { std::cout << "- bar compute() for 2" << std::endl; }

   template <int bb = b>
   typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
    { std::cout << "- bar compute() for 3" << std::endl; }
 };

两种方式都遵循完整的可编译示例

#include <iostream>
#include <type_traits>

template <int a, int b>
struct fooSub
 {
   void compute ()
    { std::cout << "- foo generic compute()" << std::endl; }
 };

template <int a>
struct fooSub<a, 2>
 {
   void compute ()
    { std::cout << "- foo compute() for 2" << std::endl; }
 };

template <int a>
struct fooSub<a, 3>
 {
   void compute ()
    { std::cout << "- foo compute() for 3" << std::endl; }
 };

template <int a, int b>
struct foo : public fooSub<a, b>
 { };

template <int a, int b>
struct bar
 {
   template <int bb = b>
   typename std::enable_if<(b == bb) && (b != 2) && (b != 3)>::type
         compute ()
    { std::cout << "- bar generic compute()" << std::endl; }

   template <int bb = b>
   typename std::enable_if<(b == bb) && (b == 2)>::type compute ()
    { std::cout << "- bar compute() for 2" << std::endl; }

   template <int bb = b>
   typename std::enable_if<(b == bb) && (b == 3)>::type compute ()
    { std::cout << "- bar compute() for 3" << std::endl; }
 };


int main()
 {
   foo<0, 1>{}.compute(); // print - foo generic compute()
   foo<1, 2>{}.compute(); // print - foo compute() for 2
   foo<2, 3>{}.compute(); // print - foo compute() for 3

   bar<2, 1>{}.compute(); // print - bar generic compute()
   bar<3, 2>{}.compute(); // print - bar compute() for 2
   bar<4, 3>{}.compute(); // print - bar compute() for 3
 }

【讨论】:

    【解决方案2】:

    由于知道模板的类型名,你可以在computeSomething函数中添加一些实现,以分支流程,如下所示:

    template <int a, int b>
    class MyTemplateClass
    {
        // ....
        void computeSomething()
        {
            if (b == 2) { computeWith2(); }
            else if (b == 3) { computeWith3(); }
            else { computerNormally(); }
        };
    }
    

    【讨论】:

      【解决方案3】:

      一种方法是将此类的计算提取到一个单独的类中。

      那么你可以只专门化那个计算类:

      template <int a, int b>
      class MyTemplateClass
      {
          // ....
          void computeSomething() {
              Computation<a, b> c;
              c.compute();
          }
      };
      template <int a, int b>
      struct Computation { void compute () {} };
      template <int a>
      struct Computation<a, 2> { void compute () {} };
      template <int a>
      struct Computation<a, 3> { void compute () {} };
      

      虽然 IMO 最好不要使用专业化,而是使用不同的(描述性!)名称和编译时间条件来在它们之间进行选择:

      template<bool Condition,
               typename Then,
               typename Else>
      using if_t = typename std:: conditional<
          Condition, Then, Else>:: type;
      
      template <int a, int b>
      class MyTemplateClass
      {
          // ....
          using Computation =
              if_t<b == 2,
                   B2Comp<a>,
                   if_t<b == 3,
                        B3Comp<a>,
                        DefaultComp<a, b> > >;
          void computeSomething() {
              Computation c;
              c.compute();
          }
      };
      // Add  (template) classes, B3Comp and DefaultComp
      

      如果你已经可以尝试C++17,那么上面可以重写为:

      template <int a, int b>
      class MyTemplateClass
      {
          // ....
          void computeSomething() {
              if constexpr (b == 2) {
                  B2Comp<a> comp;
                  comp.compute();
              } else if constexpr (b == 3) {
                  B3Comp<a> comp;
                  comp.compute();
              } else {
                  DefaultComp<a, b> comp;
                  comp.compute();
                  // Or just put the code here, if it's short
              }
          }
      };
      

      除了模板类,您还可以使用模板函数。

      与使用 normal if 相比,这避免了对“不需要的”代码路径的评估,因此可以在那里放置其他格式错误的代码(如同一模板的递归实例化)。

      【讨论】:

        猜你喜欢
        • 2013-12-27
        • 2013-02-28
        • 1970-01-01
        • 1970-01-01
        • 2016-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多