1

我有一堆结构std::array,其中包含不同数量的预先排序的size_ts。作为一个玩具示例,假设我们有以下三个结构:

struct F_A { static constexpr std::array<size_t, 4> bounds = { 0, 100, 200, 300 }; };
struct F_B { static constexpr std::array<size_t, 5> bounds = { 0, 125, 250, 300, 500 }; };
struct F_C { static constexpr std::array<size_t, 4> bounds = { 100, 250, 300, 301 }; };

目标是在编译时执行与N-way等效的操作;std::set_union例如,鉴于上述结构,我希望能够编写

constexpr auto bounds = merge_bounds<F_A,F_B,F_C>();

并最终bounds作为constexpr std::array<size_t, 8>包含值0, 100, 125, 200, 250, 300, 301, 500

合并一对结构中的bounds数组非常容易。但是,对于如何最好地将其概括为使用可变参数模板和参数包,我有点不知所措。为了使具有对的版本工作,我首先“模拟”合并以确定合并数组在实际执行合并之前将持续多长时间,但是当与参数包结合时,这种方法会变得非常麻烦。(我怀疑即使我的配对代码也远没有我能更好地处理一些相关的语言特性时那么优雅......)

这是一个 MWE,展示了我的配对功能代码:

#include <cstdlib>
#include <iostream>
#include <array>

struct F_A { static constexpr std::array<size_t, 4> bounds = { 0, 100, 200, 300 }; };
struct F_B { static constexpr std::array<size_t, 5> bounds = { 0, 125, 250, 300, 500 }; };
struct F_C { static constexpr std::array<size_t, 4> bounds = { 100, 250, 300, 301 }; };

template <typename F0, typename F1>
inline static constexpr auto merged_size()
{
    constexpr auto bnd0 = F0::bounds;
    constexpr auto bnd1 = F1::bounds;
    size_t i = 0, i0 = 0, i1 = 0;
    while (i0 < bnd0.size() && i1 < bnd1.size())
    {
             if (bnd0[i0] < bnd1[i1]) { i++; i0++;       }
        else if (bnd0[i0] > bnd1[i1]) { i++;       i1++; }
        else                          { i++; i0++; i1++; }
    }
    while (i0 < bnd0.size())          { i++; i0++;       }
    while (i1 < bnd1.size())          { i++;       i1++; }
    return i;
}

template <typename F0, typename F1, size_t N = merged_size<F0,F1>()>
inline static constexpr auto merge_bounds()
{
    std::array<size_t, N> merged = { 0 };

    constexpr auto bnd0 = F0::bounds;
    constexpr auto bnd1 = F1::bounds;
    size_t i = 0, i0 = 0, i1 = 0;
    while (i0 < bnd0.size() && i1 < bnd1.size())
    {
             if (bnd0[i0] < bnd1[i1]) { merged[i++] = bnd0[i0++];             }
        else if (bnd0[i0] > bnd1[i1]) { merged[i++] =             bnd1[i1++]; }
        else                          { merged[i++] = bnd0[i0++];      i1++;  }
    }
    while (i0 < bnd0.size())          { merged[i++] = bnd0[i0++];             }
    while (i1 < bnd1.size())          { merged[i++] =             bnd1[i1++]; }

    return std::move(merged);
}

int main(int argc, char * argv[])
{
    std::cout << merged_size<F_A,F_B>() << "," << merged_size<F_B,F_C>() << "," << merged_size<F_A,F_C>() << std::endl;
    for (auto i : merge_bounds<F_A,F_B>()) std::cout << i << " ";
    std::cout <<"\n";
    for (auto i : merge_bounds<F_B,F_C>()) std::cout << i << " ";
    std::cout <<"\n";
    for (auto i : merge_bounds<F_A,F_C>()) std::cout << i << " ";
    std::cout <<"\n";

    return 0;
}

如何概括merge_bounds以允许将任意数量的此类结构指定为模板参数?

4

1 回答 1

0

拥抱价值观。

template<class T, std::size_t N>
struct partial_array:std::array<T,N>{
  std::size_t partial=N;
  constexpr std::size_t size()const{return partial;}
  constexpr T* end()const{return this->begin()+partial;}
  //etc
};

template<class T, std::size_t N, std::size_t M, std::size_t...Ms>
constexpr partial_array<T,N+M> merge(partial_array<T,N>,partial_array<T,M>);
template<class T, std::size_t N, std::size_t M>
constexpr partial_array<T,N+(M+Ms...)> merge(partial_array<T,N> a,partial_array<T,M> b, partial_array<T,Ms>... cs){
  return merge( a, merge(b,cs...) );
}

现在您只需获取数组,将它们转换为部分数组,然后合并它们。结果是具有 constexpr 大小的 constexpr 部分数组。

将该 constexpr 大小转换为数组边界,然后复制数据。

template <class...Ts>
constexpr auto merge_bounds() {
  constexpr auto merged = merge(partial_array{Ts::bounds}...);// do some magic to make this compile; maybe deduction guilds and a ctor?
  std::array<T,merged.size()> retval = merged; // add an operator std::array<T,X> to partial array
  return retval;
}

代码可能充满了拼写错误,但我希望你能明白。

于 2021-03-28T04:33:20.217 回答