假设我有一个类似int arr[N]
的int数组,并说arr[i]
来自一个小域(例如1-10)。假设我还有一个带有公共接口(抽象类)的可变模板类
template <int... A>
class FooImpl : public Foo
{
}
问题是如何实现功能:
Foo* getFoo(int arr[N]);
或者更好:
Foo* getFoo(int* pint, int size);
哪个会返回FooImpl
模板参数对应我的数组?例如,对于arr = {4,2,6,1}
,我会得到FooImpl<4,2,6,1>
答案 0 :(得分:1)
我找到了问题的答案。诀窍是使用struct variadic模板而不是我最初尝试过的函数variadic模板。我使用带有func函数的_getFoo_impl结构,它逐个元素地构建。
假设元素在[1-5]范围内,大小&lt; = 4,然后代码如下:
class Foo
{
};
template <int...A>
class FooImpl : Foo {
};
template<int...As>
struct _getFoo_impl
{
static Foo* func(int *arr, int sz)
{
if (sz == 0)
return new FooImpl<As...>;
switch (*arr)
{
case 1: return _getFoo_impl<As..., 1>::func(arr + 1, sz - 1);
case 2: return _getFoo_impl<As..., 2>::func(arr + 1, sz - 1);
case 3: return _getFoo_impl<As..., 3>::func(arr + 1, sz - 1);
case 4: return _getFoo_impl<As..., 4>::func(arr + 1, sz - 1);
case 5: return _getFoo_impl<As..., 5>::func(arr + 1, sz - 1);
default: throw "element out of range";
}
}
};
template<int A1, int A2, int A3, int A4, int A5>
struct _getFoo_impl<A1, A2, A3, A4, A5>
{
static Foo* func(int*, int sz) {
std::terminate();
}
};
Foo* getFoo(int *arr, int size)
{
return _getFoo_impl<>::func(arr, size);
}
答案 1 :(得分:0)
您无法在课程模板中存储或生成类型
template <int... N>
class FooImpl;
将运行时整数作为模板参数。但是,如果以下内容也适合您的实际问题,您可以存储然后查找指向函数的指针
template <int... N>
R FooFun(A...);
将运行时整数作为模板参数,假设函数签名R(A...)
对于所有模板参数都是相同的。请注意,此处A...
不是一组模板参数;它只是你自己的具体函数参数类型的占位符,例如FooFun(int, int)
。
在我看来,这个公式确实适合你的问题,因为你有一个没有输入参数的工厂函数,它返回一个指向对象FooImpl<N...>
的指针,总是被视为Foo*
,所以在你的情况下{{} 1}}看起来像
FooFun
这种转换的一般解决方案是基于指向函数的查找表,并在我之前的问题this answer的adapting a non-constexpr integral value to a non-type template parameter中给出(顺便说一句现在顺利,我对它非常满意 - 我的实际实现是here)。
您的情况不同之处在于您需要多维查找表。我建议你首先定义一个只有一个整数模板参数
的函数“dispatcher”template <int... N>
Foo* FooFun();
表示多维表中的线性偏移。在这种情况下,先前的解决方案直接适用于template <int OFFSET>
R FooDispatch(A...);
。然后,您必须在编译时将FooDispatch
转换为一组多维索引OFFSET
。为此,您还需要在编译时再次了解表的维度或更好的步骤。推断出N...
参数后,N...
现在可以调用FooDispatch
。
更准确地说,这种偏移到索引转换的逻辑与Matlab的函数ind2sub完全相同,只是它是一个编译时操作。这需要一些工作,所以如果你喜欢这种方法并在最后一步需要帮助,我很乐意提供帮助。在这种情况下,我认为你最好在适当制定子问题的情况下发布一个新问题。
以上所有意味着维度的数量在编译时也是已知的,因此最终是表单的函数
FooFun<N...>(...)
可以作为界面,但
Foo* getFoo(int arr[N]);
没有多大意义;你只能在后一种情况下进行运行时检查,如果尺寸不一致,可能会抛出异常。
最后请注意,在运行时使用超出范围的索引与在普通C数组中使用超出范围的索引具有相同的效果。