使用提升 MPL 线性化索引

Using Boost MPL to Linearize Indices

本文关键字:线性化 索引 MPL      更新时间:2023-10-16

我正在做一个更大的项目来概括模板实例,并且正在努力使用 Boost MPL 和 C++03 干净线性化一些索引。用一个例子来展示我的问题是最容易的(原谅我糟糕的伪代码)。

我有 N 个任意长度的向量。假设 N 是 3,并说它们看起来像:

v0 = {1,2,3};
v1 = {4,5,6,7,8};
v2 = {9,10};

对于其中的每一个,我都有一个存储在单独向量中的索引,例如:

vectorOfIndices = {0,4,1};

我想通过以下方式将它们转换为整体索引:

0*sizeof(v1)*sizeof(v2) + 4*sizeof(v2) + 1;

我正在寻找帮助定义的元函数/类是它的概括,它应该接受两个模板参数,都是 mpl::vector 类型(包含 mpl::int_ 条目)。第一个向量将包含一系列索引(上面的 vectorOfIndices,但长度为 N),第二个向量将包含长度列表(长度为 v0、v1、v2...vN以上)。结果类型应为包含总体索引的 mpl::int_。

花了我一段时间(大量阅读...很多。。。事实证明,元编程有一个陡峭的学习曲线),但我终于有一个可行的解决方案。它不是最漂亮的,但它是我的:p。如果有人有改进建议,或者看到任何问题,我很乐意听取您的意见。

/* 
 * Computes and absolute index from a sequence of indices and vectors lengths.
 * Example:
 * 
 * Vectors:
 * v0 = {1, 2, 3}
 * v1 = {2}
 * v2 = {4, 5, 6, 7}
 * 
 * Inputs:
 * lengthsOfVectors = {3, 1, 4}
 * indexSequence = {2, 0, 3}
 * 
 * Result:
 * type = 2*(1*4) + 0*(4) + 3
 * 
 */
struct ComputeAbsoluteIndex
{
    template <typename lengthsOfVectors, typename indexSequence> struct apply
    {
        // Number of indices in sequence.
        typedef typename mpl::size<indexSequence>::type numberOfIndicesInSequence;
        // Forward sequence to iterate over number of indices in sequence.
        typedef typename mpl::range_c<int, 0, numberOfIndicesInSequence::value>::type indexSequenceRange;
        // Forward iterator that points to start of lengths of vectors. 
        // Add one since offset contributions are computed by multiplying the current index, from the index sequence, by the lengths subsequent vectors.
        typedef typename mpl::next<typename mpl::begin<lengthsOfVectors>::type >::type lengthsOfVectorsStart;
        // Forward iterator that points to the end of lengths of vectors.
        typedef typename mpl::end<lengthsOfVectors>::type lengthsOfVectorsEnd;
        typedef typename mpl::lambda // Helper metafunction class to multiply lengths.
        <
            mpl::fold // Loop over lengths to multiply.
            <
                mpl::_1, // Sequence of lengths to multiply.
                mpl::int_<1>, // Initial multiplier of one.
                typename mpl::lambda // Wrap multiply in lambda such that place holders (_1 and _2) are replaced properly.
                <
                    mpl::multiplies<mpl::_1, mpl::_2 >
                >::type
            >
        >::type multiplySequence;
        typedef typename mpl::fold // Loop over each index in index sequence.
        <
            indexSequenceRange, // Forward Sequence to iterate over number of indices in index sequence.
            mpl::int_<0>, // Initial total index of zero.
            mpl::plus // Add offsets.
            <
                mpl::_1, // Initial state to start (zero), then result of previous addition for each following iteration.
                mpl::multiplies // Multiply current index from index sequence by remaining lengths.
                <
                    mpl::at<indexSequence, mpl::_2 >, // Get current index from index sequence.
                    multiplySequence::apply // Invoke helper metafunction class to multiply lengths.
                    <
                        mpl::iterator_range // Create Forward Sequence that iterates over lengths to multiply.
                        <
                            mpl::advance<lengthsOfVectorsStart, mpl::_2>, // Advance iterator start to multiply proper lengths.
                            lengthsOfVectorsEnd
                        > 
                    >
                >
            >
        >::type type;
    };
};