11

C++11 では、STL にstd::iota関数が追加されました (参照を参照)。ただし、 とは対照的にstd::fill_nstd::generate_nはありませんstd::iota_n。そのための良い実装は何でしょうか? 直接ループ (代替 1) または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++98 と比較して C++11 で更新された方法でもあります。

4

4 に答える 4

10

ランダムな例として、次のコードを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_m2 番目のバージョンです。アセンブリは、3 つのケースすべてで次のようになります。

    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、3 つのバージョンも非常に似ていますが、かなり長くなります (条件付き移動などを使用punpcklqdq)。

于 2012-08-01T21:26:35.133 に答える