当前位置:  开发笔记 > 编程语言 > 正文

如何过滤std :: integer_sequence

如何解决《如何过滤std::integer_sequence》经验,为你挑选了2个好方法。

如果我理论上有一个整数序列像

std::integer_sequence

如何使用一些编译时谓词来过滤它以获得更小的std::integer_sequence

为了论证,让我们说我只想要偶数值,这导致了"如何使下面的static_assert(或接近的东西)通过?"的问题.

static_assert(std::is_same_v,
              decltype(FilterEvens(std::integer_sequence{}))>, 
              "Integer sequences should be equal");



这个问题的灵感来自于考虑我们如何完成删除两个位集之间的重复(这个问题),假设我们可以将位集表示为integer_sequences仅包含0和1.如果你也可以用这种方式解决那个问题



1> Barry..:

过滤序列相当于将一系列值转换为最多一个值的序列序列,然后将它们连接起来.也就是说,过滤偶数值<0,1,2,3>将与将其转换为序列<<0>,<>,<2>,<>>并连接以产生相同<0,2>.

使用C++ 17,这需要非常少的代码.我们将从我们自己的值和序列类型开始(您可以轻松地将a转换std::integer_sequence为a value_sequence):

template 
struct value { };

template 
struct value_sequence { };

我们使用自己的原因是我们可以添加运算符.喜欢+:

template 
constexpr value_sequence operator+(value_sequence,
                                                 value_sequence )
{
    return {};
}

我们将使用它进行连接.接下来,我们添加一个函数将单个值转换为零或一个元素的序列:

template 
constexpr auto filter_single(value, F predicate) {
    if constexpr (predicate(Val)) {
        return value_sequence{};
    }
    else {
        return value_sequence<>{};
    }
}

最后,我们只需要我们的顶层filter将所有内容组合在一起:

template 
constexpr auto filter(value_sequence, F predicate) {
    return (filter_single(value{}, predicate) + ...);
}

原始示例中的用法:

constexpr auto evens = filter(
    value_sequence<0, 1, 2, 3, 4, 5, 6, 7, 8, 9>{},
    [](int i) constexpr { return i%2 == 0; });

C++ 17有多酷!



2> AndyG..:

编辑2

经过Barry的回答,我得出了以下答案,它合并了概念并处理了一些空序列边缘情况(完整代码):

我们被允许谓词传递给一个函数,只有当它是一个constexpr拉姆达,因为只有文字类型允许constexpr的功能,和正常的自由浮动的功能不是文字类型(虽然我想你可以换你拉姆达中的一个).

我们的通用过滤器函数将接受序列和谓词,并返回一个新序列.我们将使用constexpr if处理空序列的情况(这也需要maybe_unused谓词的属性,因为它没有使用):

template
constexpr auto Filter(std::integer_sequence, [[maybe_unused]] Predicate pred)
{
    if constexpr (sizeof...(b) > 0) // non empty sequence
       return concat_sequences(FilterSingle(std::integer_sequence{}, pred)...);
    else // empty sequence case
        return std::integer_sequence{};
}

Filter函数调用FilterSingle提供的序列中的每个元素,并连接所有元素的结果:

template
constexpr auto FilterSingle(std::integer_sequence, Predicate pred)
{
    if constexpr (pred(a))
        return std::integer_sequence{};
    else
        return std::integer_sequence{};
}

为了连接序列,基本方法是:

template
constexpr std::integer_sequence
concat_sequences(std::integer_sequence, std::integer_sequence){
    return {};
}

虽然由于模板扩展,我们将有很多时间超过2个序列,所以我们需要一个递归的情况:

template
constexpr auto
concat_sequences(std::integer_sequence, std::integer_sequence, R...){
    return concat_sequences(std::integer_sequence{}, R{}...);
}

因为我们可能会尝试将空序列连接起来(如果没有元素通过过滤器就会发生),我们需要另一个基本情况:

template
constexpr std::integer_sequence
concat_sequences(std::integer_sequence){
    return {};
}

现在,对于我们的谓词,我们将使用constexprlambda.请注意,我们不需要constexpr明确指定它,因为它已满足自动变为的条件constexpr

auto is_even = [](int _in) {return _in % 2 == 0;};

所以我们的完整测试看起来像这样:

auto is_even = [](int _in) {return _in % 2 == 0;};
using expected_type = std::integer_sequence;
using test_type = std::integer_sequence;
constexpr auto result = Filter(test_type{}, is_even);
using result_type = std::decay_t;
static_assert(std::is_same_v, "Integer sequences should be equal");

以前的方法

我的方法是重复构造和连接子序列,其中基本情况(一个序列)将返回空序列或如果满足谓词则返回相同的序列.

为了编写谓词,如果用于定义谓词,我将利用C++ 17的constexpr.

谓语:

// base case; empty sequence
template
constexpr auto FilterEvens(std::integer_sequence)
{
    return std::integer_sequence{};
}

// base case; one element in the sequence
template
constexpr auto FilterEvens(std::integer_sequence)
{
    if constexpr (a % 2 == 0)
        return std::integer_sequence{};
    else
        return std::integer_sequence{};
}

// recursive case
template
constexpr auto FilterEvens(std::integer_sequence)
{
    return concat_sequence(FilterEvens(std::integer_sequence{}), 
                           FilterEvens(std::integer_sequence{}));
}

连接逻辑:

template 
constexpr auto
concat_sequence(std::integer_sequence,std::integer_sequence){
   return std::integer_sequence{};
}

而且测试:

int main()
{
   static_assert(std::is_same_v, decltype(FilterEvens(std::integer_sequence{}))>, "Integer sequences should be equal");
}

现场演示


编辑:

我使用这种方法来解决在这里删除匹配位的"奖励"问题:https://stackoverflow.com/a/41727221/27678

推荐阅读
黄晓敏3023
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有