4

申し訳ありませんが、これは配列に関する 3 つの質問になりました

(動的) 配列は D では本当に強力だと思いますが、次のことがしばらく気になりました。

C++ では、指定された値で配列を簡単に割り当てることができましたが、DI ではその方法が見つかりませんでした。確かに、次のことは問題ありません。

int[] a = new int[N];
a[] = a0;

0しかし、1 行目は で初期化され、2行目は で初期化されるため、効率が悪いように見えますa0。次のようなことを D で行うことはできますか?

int[] a = new int(a0)[N]; // illegal

std.range でストライドを使用するときのもう 1 つの効率の問題:

import std.stdio;
import std.range;

struct S
{
    int x;

    this(this)
    {
        writeln("copy ", x);
    }
}

void f(S[] s)
{
}

int main()
{
    S[] s = new S[10];
    foreach (i, ref v; s)
    {
        v.x = i;
    }

    f(stride(s, 3)); // error
    return 0;
}

確かに、ストライドを使用して、要素をコピーせずに新しい配列を作成できると単純に考えていたのでしょうか。Dではそうする方法はありませんよね?


そこで、配列がストライドが返すようにシミュレートし、次のように実装fしました。

f(s, 3);

void f(S[] s, uint stride)
{
    ref S get(uint i)
    {
        assert (i * stride < s.length);
        return s[i * stride];
    }

    for (uint x ... )
    {
        get(x) = ...;
    }
}

インデックス演算子を使用して代わりに get(x) を記述する方法はありますget[x]か? このようにして、ストライディング関数を静的にミックスイン/インクルードしget、残りの関数を同様に保つことができました。ローカル構造体は関数スコープ変数にアクセスすることが許可されていないため、採用されたアプローチに興味があります(なぜですか?)。

4

2 に答える 2

7

しかし、1 行目は 0 で初期化され、2 行目は a0 で初期化されるため、効率が悪いように見えます。次のようなことを D で行うことはできますか?

使用するstd.array.uninitializedArray

S[] s = uninitializedArray!(S[])(N);
s[] = a0; 

確かに、ストライドを使用して、要素をコピーせずに新しい配列を作成できると単純に考えていたのでしょうか。Dではそうする方法はありませんよね?

あなたの関数fにはS[]引数としてがあり、これは返されるものとは異なりstrideます。これを解決する D の方法は、f関数をテンプレートにして任意の範囲を受け入れるようにすることです。

void f(Range)(Range s)
{
    foreach (item; s)
        // use item
}

S[] s = new S[10];
f(s); // works
f(stride(s, 3)); // works too

または、配列をコピーすることもできます:

f(array(stride(s, 3)));

ただし、配列が大きい場合は、配列全体をコピーすることは避けた方がよいでしょう。


代わりに、インデックス演算子 get[x] を使用して get(x) を記述する方法はありますか? このようにして、ストライディング get 関数を静的にミックスイン/インクルードし、残りの関数を同様に保つことができました。ローカル構造体は関数スコープ変数にアクセスすることが許可されていないため、採用されたアプローチに興味があります(なぜですか?)。

独自の構造体でインデックス演算子をオーバーロードできます。

struct StrideArray
{
    this(S[] s, uint stride) { m_array = s; m_stride = stride; }

    S opIndex(size_t i) { return s[i * m_stride]; }
    void opIndexAssign(size_t i, S value) { s[i * m_stride] = value; }

    private S[] m_array;
    private uint m_stride;
}

これは、実際の関数が機能する (一種の) 方法strideです。Rangesを読むことをお勧めします。

于 2011-12-03T00:25:05.583 に答える
1

.dup を使用して配列を複製 (コピーを作成) したり (これはスライスでも機能します)、配列初期化子を使用して要素を設定したりできます。

int[] a=a0.dup;
int[] b=[e1,e2,e3];

f をジェネリックにすることができます (stride() は、配列ではなく、反復できる構造体を返します)

void f(Z)(Z s)if(isInputRange!Z){
    foreach(elem;s){
         //...
    }
}

配列は基本的に、メモリ ブロックへのポインタ フィールドとサイズ フィールドを持つ構造体であることを思い出してください。

于 2011-12-03T00:19:01.640 に答える