这将是一个良好的执行iota_n的(缺少从STL算法)(What would be a good i

2019-06-26 17:15发布

用C ++ 11,STL现在具有std::iota函数(见参考 )。 与此相反std::fill_nstd::generate_n ,没有std::iota_n ,但是。 这将是一个很好的实现是什么? 直接循环(备选1)或委派std::generate_n用一个简单的lambda表达式(备选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 ++ 98 C ++ 11。

Answer 1:

作为随机例如,我编译用下面的代码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以及诸如此类)。



Answer 2:

你太专注于代码生成,你忘了帮接口权利。

您需要正确的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());


文章来源: What would be a good implementation of iota_n (missing algorithm from the STL)