iota_n(STL中缺少的算法)的一个好的实现
What would be a good implementation of iota_n (missing algorithm from the STL)
有了C++11,STL现在有了std::iota
函数(请参阅参考资料)。然而,与std::fill_n
、std::generate_n
相比,没有std::iota_n
。什么是一个好的实施?直接循环(备选方案1)或用简单lambda表达式委派给std::generate_n
(备选方案2)?
备选方案1)
template<class OutputIterator, class Size, class T>
OutputIterator iota_n(OutputIterator first, Size n, T value)
{
while (n--)
*first++ = value++;
return first;
}
备选方案2)
template<class OutputIterator, class Size, class T>
OutputIterator iota_n(OutputIterator first, Size n, T value)
{
return std::generate_n(first, n, [&](){ return value++; });
}
这两种选择都会通过优化编译器生成等效的代码吗?
UPDATE:结合了@Marc Mutz的优点,也在其目的点返回迭代器。这也是std::generate_n
在C++11中与C++98相比的更新方式。
作为一个随机示例,我使用g++ -S -O2 -masm=intel
(GCC 4.7.1,x86_32)编译了以下代码:
void fill_it_up(int n, int * p, int val)
{
asm volatile("DEBUG1");
iota_n(p, n, val);
asm volatile("DEBUG2");
iota_m(p, n, val);
asm volatile("DEBUG3");
for (int i = 0; i != n; ++i) { *p++ = val++; }
asm volatile("DEBUG4");
}
这里iota_n
是第一个版本,iota_m
是第二个版本。组件在所有三种情况下都是这样的:
test edi, edi
jle .L4
mov edx, eax
neg edx
lea ebx, [esi+edx*4]
mov edx, eax
lea ebp, [edi+eax]
.p2align 4,,7
.p2align 3
.L9:
lea ecx, [edx+1]
cmp ecx, ebp
mov DWORD PTR [ebx-4+ecx*4], edx
mov edx, ecx
jne .L9
对于-O3
,这三个版本也非常相似,但很多更长(使用条件移动和punpcklqdq
等)。
您过于专注于代码生成,以至于忘记了正确处理接口。
您正确地要求OutputIterator
,但如果您想再次调用它,会发生什么?
list<double> list(2 * N);
iota_n(list.begin(), N, 0);
// umm...
iota_n(list.begin() + N, N, 0); // doesn't compile!
iota_n(list.rbegin(), N, 0); // works, but create 0..N,N-1..0, not 0..N,0..N
auto it = list.begin();
std::advance(it, N);
iota_n(it, N, 0); // works, but ... yuck and ... slow (O(N))
在iota_n
中,您仍然知道自己在哪里,但您已经丢弃了这些信息,因此调用者无法在恒定时间内获取这些信息。
一般原则:不要丢弃有用的信息。
template <typename OutputIterator, typename SizeType, typename ValueType>
auto iota_n(OutputIterator dest, SizeType N, ValueType value) {
while (N) {
*dest = value;
++dest;
++value;
--N;
}
// now, what do we know that the caller might not know?
// N? No, it's zero.
// value? Maybe, but it's just his value + his N
// dest? Definitely. Caller cannot easily compute his dest + his N (O(N))
// So, return it:
return dest;
}
有了这个定义,上面的例子就变得简单了:
list<double> list(2 * N);
auto it = iota_n(list.begin(), N, 0);
auto end = iota_n(it, N, 0);
assert(end == list.end());
一个假设的iota_n
std::iota_n(first, count, value)
可以用一个衬垫代替。
std::generate_n(first, count, [v=value]()mutable{return v++;})
我更喜欢这个有一个标准中没有的延迟函数。话虽如此,我认为std::iota_n
应该在标准中。
可能将back_insertor与std::generate_n一起使用,这样可以避免集合的预分配。
vector<int> v3;
generate_n(back_inserter(v3),10,[i=1]() mutable{
return i++;
});
我们可以将其交换为iota_n,直到我们得到iota_n:)
- 实现一个在集合上迭代的模板函数
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践
- 为什么我们要为avl树实现返回一个指向节点的指针,而不是void函数
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 为什么在排序链表上的这种合并实现总是将两个列表都设置为 NULL,而只有一个应该设置一个列表?
- 如何为位集找到/实现一个好的哈希函数
- C++哈希表中,两个相同的实现,但一个给出错误
- 如何将这两个函数组合成一个实现?
- 类中的数组变量C++导致"was not declared in this scope"实现文件的一个函数中错误,但在构造函数中不会导致错误
- 为什么这个快速排序实现给出了一个奇怪的输出
- C++:实现一个全局常量,其值由用户给出
- C++:实现一个接收lambda作为输入的高阶函数
- std::sort 一个实现了移动构造函数的类
- GMock - 用另一个实现模拟抽象类
- 有没有办法(C++)创建一个实现某些功能的模板类?
- 创建一个实现选项卡并可用作 QMainWindow 中的"central widget"的类
- 说出一个实现STL兼容序列容器的好指南)
- 一个C++实现的隐马尔可夫模型林安装错误
- 一个实现是否允许在同一地址放置两个相同的函数定义