C++:如何用单个命令替换复杂的迭代?
C++: How to replace a complex iteration with a single command?
问题
我有时会有复杂的迭代过程,必须在代码中重复几次,但在每次迭代中执行的表达式在代码的不同位置都不同。必须在任何地方重写迭代过程是丑陋的,并且容易出错。如何包装此迭代过程?
例
例如,考虑这个相对复杂的迭代
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
// print integers and permute bitmask
do {
// Loop through BIG and SMALL indices
for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
{
size_t nbSmalls;
if (BIGindex == nbBigs)
{
nbSmalls = nbSmallsOfLastBig;
} else
{
nbSmalls = nbSmallsStandard;
}
for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
{
// doStuff with bitmask, BIGindex and SMALLindex
}
}
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
如何定义一个命令/别名(因为缺乏更好的词(,例如"doComplexIteration",它将所有这些迭代包装成一个更简单的命令。类似的东西
doComplexIteration
{
// doStuff with bitmask, BIGindex and SMALLindex
}
一个不完全令人满意的解决方案
一种方法是将要完成的事情包装在函数中,例如
void doComplexIterationOnFunction(void (*doStuff)(std::string bitmask, size_t BIGindex, size_t SMALLindex))
{
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
// print integers and permute bitmask
do {
// Loop through BIG and SMALL indices
for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
{
size_t nbSmalls;
if (BIGindex == nbBigs)
{
nbSmalls = nbSmallsOfLastBig;
} else
{
nbSmalls = nbSmallsStandard;
}
for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
{
(*doStuff)(bitmask, BIGindex, SMALLindex);
}
}
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
然后调用它为
doComplexIterationOnFunction(doSpecificStuff);
但是,它迫使我系统地将我希望在每次迭代中执行的任何代码包装在一个函数中,这有点麻烦和有点愚蠢,因为有时代码很短。
无需使用函数指针,您只需将函数设置为模板类型,然后允许您在调用站点传递 lambda。 那看起来像
temaplte<typename Function>
void doComplexIterationOnFunction(Function doStuff)
{
std::string bitmask(K, 1); // K leading 1's
bitmask.resize(N, 0); // N-K trailing 0's
// print integers and permute bitmask
do {
// Loop through BIG and SMALL indices
for (size_t BIGindex = 0; BIGindex < nbBigs; ++BIGindex)
{
size_t nbSmalls;
if (BIGindex == nbBigs)
{
nbSmalls = nbSmallsOfLastBig;
} else
{
nbSmalls = nbSmallsStandard;
}
for (size_t SMALLindex = 0; SMALLindex < nbSmalls; ++SMALLindex)
{
std::invoke(doStuff, bitmask, BIGindex, SMALLindex);
}
}
} while (std::prev_permutation(bitmask.begin(), bitmask.end()));
}
然后你会这样称呼它
doComplexIterationOnFunction(doSpecificStuffFunction) // pass function
doComplexIterationOnFunction(doSpecificStuffFuntor) // pass functor
doComplexIterationOnFunction([](auto foo, auto bar, auto baz) { return foo + bar - baz; }) // pass lambda
有一个不同的选项:
反转控件,方法是编写一个范围,或者至少足够多的范围来使用 range-for:
struct ComplexIterationRange {
static constexpr auto end() noexcept { struct {} r; return r; }
static auto begin() {
struct {
std::string bitmask;
std::size_t SMALLindex = 0, BIGindex = 0;
const auto& operator*() const noexcept { return *this; }
auto& operator++() noexcept {
if (++SMALLindex >= nbSmallsStandard) {
if (++BIGindex >= nbBigs) {
if (!std::prev_permutation(bitmask.begin(), bitmask.end()))
return *this;
BIGindex = 0;
}
SMALLindex = 0;
}
return *this;
}
bool operator!=(decltype(end())) const noexcept {
return SMALLindex < nbSmallsStandard || BIGindex < nbBigs;
}
} r { []{ std::string r(K, 1); r.resize(N, 0); return r; }() };
return r;
}
};
像这样使用它:
for (auto&& x : ComplexIterationRange()) {
Use x.SMALLindex, x.BIGindex, and x.bitmask here
...
}
与将函数指针甚至 lambda 传递给模板函数相比,它的优势在于调用方具有更大的灵活性和控制力。
代价是在编写范围时将您的大脑打结。
相关文章:
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 迭代时从向量和内存中删除对象
- 如何在c++迭代器类型中包装std::chrono
- 带过滤器的现代迭代c++集合
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- C++矢量迭代
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 擦除while循环中迭代的元素
- 实现一个在集合上迭代的模板函数
- 对于set上的循环-获取next元素迭代器
- C++:如何用单个命令替换复杂的迭代?
- 如何为指向复杂值的迭代器专门化算法?
- 复杂数据类型向量的迭代器
- 具有复杂值类型的迭代器:与value_type和引用混淆
- 复杂范围的多个迭代器
- 迭代算法的时间复杂度
- 迭代c++ unordered_map的时间复杂度