C++ 填写C++;根据模式使用数字数组

C++ 填写C++;根据模式使用数字数组,c++,lambda,c++17,C++,Lambda,C++17,我有一个填充数组的模式: 偶数指数值=-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(),

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

偶数指数值=-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);
#包括
#包括
使用名称空间std;
int生成器(){
静态int i=1;
i*=-1;
返回i;
}
std::阵列arr;
std::generate(arr.begin()、arr.end()、generator);
编辑:当前实现有一个警告-返回值
generator
不依赖于迭代的对象索引


是否有办法将当前索引传递给
生成器
函数,使其输出取决于此索引?

正如@cigen所指出的,您的代码按编写的那样工作

但要回答您的问题,“有没有办法将当前索引传递给生成器函数?”——答案是“没有,不是使用
std::generate
”。下面是该调用的示例实现(取自:

模板
void generate(ForwardIt first,ForwardIt last,Generator g)
{
while(第一个!=最后一个){
*第一个+++=g();
}
}
注意事项:

  • generate
    的这个实现不使用索引,因此不能将它们传递给生成器
  • generator函数为空(不带参数),因此generate无法通过索引,即使它有索引

如果要将状态附加到函数,最好使用函数对象而不是函数局部静态变量(因为您发现的原因:可重用性)

Ret类型必须是ForwardIt类型的对象 取消引用并分配Ret类型的值。​


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

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

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

// usage ...

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

这里有一个。

您不能使用
std::generate
将当前索引传递给
生成器
函数。 但您可以使用lambda来执行此操作:

std::数组arr;
自动生成器=[i=1,n=0]()可变{
//n是这里的当前索引
i=-i;
n++;
返回i;
};
std::generate(arr.begin()、arr.end()、generator);

所有解决方案都假定生成器将按顺序调用,那么并行和无序执行又如何呢

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;});
或:

std::数组arr;
std::ranges::copy(std::views::iota(decltype(arr)::size_type{},arr.size())| std::views::transform([](自动常量i){返回i%2?-1:1;}),arr.begin());

您可以并行和/或无序运行此操作,也可能有其他解决方案。

仅仅因为难以使用
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++);
    }
  }
}
名称空间mystl{
模板
void generate(ForwardIt first,ForwardIt last,Generator g)
{
int-idx=0;
while(第一个!=最后一个){
*第一+++=g(idx++);
}
}
}

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

你所说的“将当前索引传递给生成器”到底是什么意思??这段代码似乎已经实现了你想要的功能(除了奇数索引为1,偶数索引为-1)。你是在问如何将
生成器
编写为lambda吗?@cigien:我想他的意思是,如果你再次调用它,它可能会失败,因为静态变量没有被重新初始化。所以他想要一个可以多次调用的。你似乎在问如何用参数声明函数。但是为什么?哟你的代码有效,不是吗?你试图解决的问题是什么?请提供一个例子来说明这个问题。@joepol请编辑这个问题并添加你的额外关注点。我相信Nicol Bolas是正确的。一行代码:
std::generate(arr.begin(),arr.end(),[v=-1]()可变{return v=-v;};
auto gen() 
{
    return [i = -1]() mutable 
    { 
       i *= -1; 
       return i; 
    };
}

// usage ...

std::generate(arr.begin(), arr.end(), gen());
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;});
  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());
namespace mystl {
  template<class ForwardIt, class Generator>
  void generate(ForwardIt first, ForwardIt last, Generator g)
  {
    int idx = 0;
    while (first != last) {
        *first++ = g(idx++);
    }
  }
}