C++部分模板特化:成员函数

3
我有一个模板。
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
}

然而,据我所知,对于成员函数来说,部分特化是无效的。我该怎么做才能达到我想要的效果呢?是否还有其他解决方案?谢谢!


2
你需要对整个类进行部分特化,或者创建几个重载的模板方法来处理特定的主类特化。 - user7860670
3个回答

5
一种可能的方式是提取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,另一个可能的解决方案是通过以下bar类中的SFINAE(std::enable_if)激活/停用不同版本的compute()
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
 }

1

由于模板的类型名称已知,您可以在computeSomething函数中添加一些实现来分支流程,例如:

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

1
一种方法是将此类中的计算提取到单独的类中。
然后您可以专门针对该计算类进行操作:
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 () {} };

尽管我认为最好不要使用特化,而是使用不同(描述性!)名称和编译时条件来选择它们:
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
        }
    }
};

你可以使用模板函数代替模板类。

与使用普通if不同,这避免了对“不需要”的代码路径进行评估,从而使得可以在那里放置其他无效的代码(例如同一模板的递归实例化)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接