1

GPU デバイスでポインターを表す型をコーディングしようとしていますが、get と set のインデックス付きプロパティを使用して、配列のように動作する必要があります。要素の型がプリミティブ型であれば問題ないのですが、構造体を使うとメンバの値を変更できません。

このコードを参照してください:

#nowarn "9"

open System
open System.Runtime.InteropServices

[<Struct;StructLayout(LayoutKind.Sequential)>]
type MyStruct =
    val mutable x : int
    val mutable y : int
    val mutable z : int

    override this.ToString() = sprintf "(%d,%d,%d)" this.x this.y this.z

let deviceOnly() = failwith "this function should be used in quotation only"

type DevicePtr<'T>(h:nativeint) =
    member this.Handle = h
    member this.Item with get (idx:int) : 'T = deviceOnly() and set (idx:int) (value:'T) : unit = deviceOnly()
    member this.Reinterpret<'T2>() = DevicePtr<'T2>(h)
    member this.Volatile() = DevicePtr<'T>(h)
    static member (+) (ptr:DevicePtr<'T>, offset:int) = DevicePtr<'T>(ptr.Handle + nativeint(offset * sizeof<'T>))

let test() =
    let mutable test1 = MyStruct()
    test1.x <- 1

let foo (collection:MyStruct[]) =
    collection.[0].x <- 1

let bar (collection:DevicePtr<MyStruct>) =
    collection.[0].x <- 1
    //error FS0257:
    // Invalid mutation of a constant expression.
    // Consider copying the expression to a mutable local, e.g. 'let mutable x = ...'.

したがって、型は DevicePtr<'T> であり、get メソッドと set メソッドの両方を持つインデックス付きプロパティ Item があります。しかし、get メソッドは 'T の値を返すだけなので、それを変更することはできません。しかし、システム配列は機能します。

このような経験をしたことがある人はいませんか?配列のように機能する型を作成するには? インデックス付きプロパティの get 関数が、値ではなく変更可能な参照を返すことを願っています。

4

1 に答える 1

2

配列のような構造で機能する型を作成することはできません。これは、言語とランタイムが、他のクラスでは得られない特別な処理を配列に与えるためです。

配列では、関数のように、構造体である要素にアクセスする式により、要素がそのfoo場で直接変更されます。はcollection.[0]、式が適用される要素への「ポインター」または「参照」を効果的に設定し.x、オブジェクトをその場で操作できるようにします。

他のクラスの場合、インデクサーは単なる別の関数であり、値のコピーが返されることを意味します。そのため、bar関数ではcollection.[0]、配列から取得した参照ではなく、返された値のコピーを作成します。は一時コピーを変更するため.x、コンパイラは表示されるエラーを発行します。(同様のコードに対して、C# または VB で非常によく似た警告が発生します。) メッセージが示すように、コピーを保持する変数を作成し、コピーを変更して、それを に割り当てる必要がありますcollection.[0]

于 2013-04-04T04:32:24.700 に答える