繁体   English   中英

根据模式用数字填充 C++ 数组

[英]Fill a C++ array with numbers according to a pattern

我有一个要填充数组的模式:

偶数索引值 = -1

奇数索引值 = 1

我目前是这样实现的:

#include <array>
#include <algorithm>

using namespace std;
int generator(){
    static int i = 1;
    i *= -1;
    return i;
}

std::array<int ,64> arr;
std::generate(arr.begin(), arr.end(), generator);

编辑:当前实现有一个警告 - generator的返回值不依赖于迭代的 object 索引。

有没有办法将当前索引传递给generator function 所以它的 output 将取决于这个索引?

您的generator function 有一个static局部变量,它在每次调用中保留其 state。 这意味着如果您在不同的调用中使用generator ,它会记住它的旧 state,这可能不是您想要的。

您可以通过编写 function 来解决此问题,每次调用它时都会为您提供一个“生成器”。 请注意,返回的值(即生成器本身)只是一个mutable的 lambda,因此i的值在多次调用该 lambda 时被保留。

auto gen() 
{
    return [i = -1]() mutable 
    { 
       i *= -1; 
       return i; 
    };
}

// usage ...

std::generate(arr.begin(), arr.end(), gen());

这是一个演示

正如@cigen 所指出的,您的代码按照编写的方式工作。

但是要尝试回答您的问题,“有没有办法将当前索引传递给生成器 function?” - 答案是“不,不是std::generate ”。 这是该调用的示例实现(取自CppReference

template<class ForwardIt, class Generator>
void generate(ForwardIt first, ForwardIt last, Generator g)
{
    while (first != last) {
        *first++ = g();
    }
}

注意事项:

  • generate的这个实现不使用索引,因此它不能将它们传递给生成器。
  • 生成器 function 是空的(它不带参数),因此即使有索引,generate 也无法传递索引。

所有的解决方案都假设您的生成器将被顺序调用,那么并行和无序执行呢?

std::array<int, 64> arr;
std::iota(arr.begin(), arr.end(), 0);
std::transform(arr.begin(), arr.end(), arr.begin(), [](auto const i){return i % 2: -1 : 1;});

您想使用错误的 function。 如果元素索引是生成器的参数,则std::transform()更适合您的要求。

编辑:您需要 c++20 来获得权威的解决方案:

  std::array<int, 64> arr;
  auto const g(std::views::iota(decltype(arr)::size_type{}, arr.size()));
  std::transform(g.begin(), g.end(), arr.begin(), [](auto const i){return i % 2 ? -1 : 1;});

或者:

  std::array<int, 64> arr;
  std::ranges::copy(std::views::iota(decltype(arr)::size_type{}, arr.size()) | std::views::transform([](auto const i){return i % 2 ? -1 : 1;}), arr.begin());

您可以并行和/或乱序运行它,并且可能还有其他解决方案。

If you want to attach state to a function it is better to use a function object rather than function local static variables (for the very reason you discovered: reusability).

struct generator2 {
    bool even = true;
    int operator()(){
        even = !even;
        return even ? -1 : 1;
    }
};

int main() {
    std::array<int ,64> arr;
    std::generate(arr.begin(), arr.end(), generator2{});
    for (auto e : arr) std::cout << e;
}

这里传递给std::generate的是一个generator2类型的实例,它的operator()将被调用。

有没有办法将当前索引传递给生成器 function?

std::generate的生成器必须可以在没有参数的情况下调用:

function 的签名应该等同于以下内容:

 Ret fun();

Ret 类型必须使得 ForwardIt 类型的 object 可以被取消引用并分配一个 Ret 类型的值。

仅仅因为std::generate很难做到并不意味着它不能做到。 您可以编写自己的generate版本:

namespace mystl {
  template<class ForwardIt, class Generator>
  void generate(ForwardIt first, ForwardIt last, Generator g)
  {
    int idx = 0;
    while (first != last) {
        *first++ = g(idx++);
    }
  }
}

不受标准算法的限制; 标准库中的大多数都没有什么神奇之处。 不要害怕自己写!

您不能使用std::generate将当前索引传递给generator function 但是您可以使用lambda来做到这一点:

std::array<int ,64> arr;
auto generator = [i = 1, n = 0] () mutable {
    // n is the current index here
    i = -i;
    n++;
    return i;
};
std::generate(arr.begin(), arr.end(), generator);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM