如何解决功能模板的局部特化?

时间:2014-03-07 15:18:21

标签: c++ templates template-specialization

例如,我有一个班级:

class A
{
    enum {N = 5};
    double mVariable;

    template<class T, int i>
    void f(T& t)
    {
        g(mVariable); // call some function using mVariable.
        f<T, i+1>(t); // go to next loop
    }

    template<class T>
    void f<T, N>(T& t)
    {} // stop loop when hit N.
};

功能模板中不允许部分特化。在我的案例中如何解决这个问题?

我略微改变了Arne Mertz的例子,如:

template<int n>
struct A
{
    enum {N = n};
    ...
};

并使用A之类的:

A<5> a;

我无法在Visual Studio 2012上编译。它是编译器错误还是其他什么?这很奇怪。

编辑:已检查。这是一个Visual Studio错误。 :(

我认为Nim提供了实现它的最简单方法。

4 个答案:

答案 0 :(得分:7)

最直接的解决方案是使用模板类而不是函数:

class A
{
    enum {N = 5};
    double mVariable;

    template <class T, int i>
    struct fImpl {
      static_assert(i<N, "i must be equal to or less than N!");
      static void call(T& t, A& a) {
        g(a.mVariable);
        fImpl<T, i+1>::call(t, a);
      }
    };

    template<class T>
    struct fImpl<T,N> {
      static void call(T&, A&)  {} // stop loop when hit N.
    };

 public:

    template<class T, int i>
    void f(T& t)
    {
        fImpl<T, i>::call(t,*this);
    }

};

Example link

答案 1 :(得分:4)

您可以定义辅助类:

template <int i, int M>
struct inc_up_to
{
  static const int value = i + 1;
};

template <int i>
struct inc_up_to<i, i>
{
  static const int value = i;
};


template<class T, int i>
void f(T& t)
{
    if (i < N) {
        g(mVariable); // call some function using mVariable.
        f<T, inc_up_to<i, N>::value>(t);
    }
}

它通过使f<T, N>引用f<T, N>来停止编译时递归,但是运行时条件可以避免该调用,从而打破循环。

也可以使用简化且更强大的帮助程序版本(感谢@ArneMertz):

template <int i, int M>
struct inc_up_to
{
  static const int value = (i >= M ? M : i + 1); // this caps at M
  // or this:
  static const int value = (i >= M ? i : i + 1); // this leaves i >= M unaffected
};

这甚至不需要部分专业化。

答案 2 :(得分:3)

支持c ++ 11,您可以执行以下操作:

#include <iostream>
#include <type_traits>
using namespace std;

struct A
{
    enum {N = 5};
    double mVariable;

    void g(int i, double v)
    { std::cout << i << "  " << v << std::endl; }

    template<int i, class T>
    typename enable_if<i >= N>::type f(T& t)
    {} // stop loop when hit N.

    template<int i, class T>
    typename enable_if<i < N>::type f(T& t)
    {
        g(i, mVariable); // call some function using mVariable.
        f<i+1, T>(t); // go to next loop
    }

};

int main(void)
{
    A a;
    int v = 0;
    a.f<0>(v);
}

我喜欢的主要原因是你不需要以前答案所要求的任何瑕疵......

答案 3 :(得分:2)

您可以使用函数重载来模拟函数模板的部分特化:

#include <type_traits>

class A
{
    enum {N = 5};
    double mVariable;

    // ...

    void g(double)
    {
        // ...
    }

public:

    template<class T, int i = 0>
    void f(T& t, std::integral_constant<int, i> = std::integral_constant<int, i>())
    {
        g(mVariable);
        f(t, std::integral_constant<int, i + 1>());
    }

    template<class T>
    void f(T& t, std::integral_constant<int, N>)
    {
    }

};

使用示例:

A a;
int t = 0;

a.f(t);
a.f(t, std::integral_constant<int, 2>()); // if you want to start loop from 2, not from 0

它是一个C ++ 11解决方案(但不是因为std::integral_constant类,而是因为函数模板的默认模板参数)。使用一些额外的C ++ 11功能可以缩短它:

template<int i>
using integer = std::integral_constant<int, i>;

template<class T, int i = 0>
void f(T& t, integer<i> = {})
{
    g(mVariable);
    f(t, integer<i + 1>());
}

template<class T>
void f(T& t, integer<N>)
{
}