例如,我有一个班级:
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提供了实现它的最简单方法。
答案 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);
}
};
答案 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>)
{
}