将int数组转换为可变参数模板

时间:2014-03-23 10:41:16

标签: c++ arrays int variadic-templates non-type

假设我有一个类似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>

2 个答案:

答案 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 answeradapting 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数组中使用超出范围的索引具有相同的效果。