5

(具体的なコンパイラ/プラットフォーム コンテキストについては、x86_64 で GCC 4.7 と Ubuntu 12.04 を使用します)

ある関数 f が与えられた場合:

void f(int x, int y);

int nx = ...;
int ny = ...;

(0,0) から (nx,ny) までのすべての値 (x,y) を反復する 1 つの方法は次のとおりです。

for (int x = 0; x < nx; x++)
    for (int y = 0; y < ny; y++)
        f(x,y);

これをコンパイルして、生成されたコード Q1 にします。

次のような関数 g を書きます。

for (auto it : g(Z))
    f(it.x, it.y);

コード Q2 にコンパイルされます。

Q2がQ1と同じくらい効率的であるようにgを書くことは可能ですか? はいの場合、どのように?そうでない場合、私たちが得ることができる最も近いものは何ですか?

役立つ場合は、 auto を auto& または auto&& に変更できます。

it.x を it.x() に変更したり、it.y を it.y() に変更したりすることもできます。

(範囲ベースの for の展開は、選択したイテレータのような型であることを思い出してください: C++11: 範囲ベースの for ステートメント: "range-init"lifetime? )

4

2 に答える 2

3

Q2がQ1と同じくらい効率的であるようにgを書くことは可能ですか? はいの場合、どのように?そうでない場合、私たちが得ることができる最も近いものは何ですか?

for確かに可能です。ループと同じ方法でインクリメントする反復子を定義するだけです。頭のてっぺんから:

class matrix_iterator
{
public:
    ...

    matrix_iterator& operator++()
    {
        if( ++y >= ny )
        {
            ++x;
            y = 0;
        }

        return *this;
    }

private:
    int nx, ny;
    int x, y;
};
于 2012-05-31T02:38:37.063 に答える
2

このコードには、必要な機能があります。私はそれを検証していませんが、元のループとほぼ同じマシン コード (最適化されたコンパイルで) を生成すると思われます。

struct iter {
    int x, y, ny;
    iter(int x, int y, int ny) : x(x), y(y), ny(ny) {}
    iter &operator++ () {
        if (++y >= ny)
        {
            y = 0;
            ++x;
        }
        return *this;
    }
    bool operator != (iter const &rhs) const {
        return y != rhs.y || x != rhs.x;
    }
};

struct container {
    iter endit;
    container(int nx, int ny) : endit(nx, ny, ny) {}
    iter begin() const { return iter(0,0,endit.ny); }
    iter const &end() const { return endit; }
};

container g(Z const &z) { return container(z.nx, z.ny); }

for ( auto it : g(Z) )
    f(it.x, it.y);
于 2012-05-31T02:48:11.403 に答える