2017-02-24 28 views
1

通過抽象提供對變量的只讀訪問權限(當然可以)。例如,我可以使變量爲模式參數的可調用實體或通用。變量的使用(通過這些常量視圖)將被限制在可調用或泛型實例中。如何使變量只讀,但不是常量?

這個結構不容易添加到現有的程序,我想,因爲程序已經結構化;此外,它不是一個獨立的解決方案,因爲它需要「只讀」和結構之間的耦合。

另一種選擇是使變量private並導出返回其值的函數。但是,我想要直接曝光,例如的一個易變的常數,仍然是從不同的角度來看變量。

我想出了一個覆蓋:

with Interfaces; 

package Read_Only is 
    subtype Pins is Interfaces.Unsigned_16; 

    V : constant Pins with Volatile, Import; 

private 
    Backing : Pins with Volatile; 
    for V'Address use Backing'Address; 
    procedure Reset; 
end Read_Only; 

該屏蔽V所以只有封裝體(和孩子)可以修改它的價值,而包的客戶端可以讀取V。但是,「隱藏」所有這些方面和地址的背後讓我想:還有其他更明顯的方式嗎?

編輯:由@ flyx的評論提醒,包將看到constant的公共部分的讀者和很可能認爲V是物理常數,它不是,是volatile。我更希望能夠保留這兩個類似於對象的字符V以及它不能從Read_Only以外改變的事實。 V這裏實際上並不是一個常量對象,但它的聲明是這樣說的。我想我想宣佈對一個可識別的易變對象或某個對象的持續觀點,而不會引發功能的突發事件。

+0

難道編譯器允許基於這樣的事實,'V'是'constant',這將打破你的代碼做一些優化,因爲它不是實際上不變?我也會說一個函數是最好的方法,因爲它告訴用戶和編譯器該值可能會隨時間而改變。 – flyx

+0

我不認爲編譯器可以優化,如果有的話(你有什麼想法?),在** volatile **的存在 - 儘管它可能內聯一個函數返回一個副本或引用(如果可能的話)一個易變的變量。但是,如何優化帶走**常數**?我會說,這個編譯器會被嚴重破壞。此外,** volatile **可以防止軟件包成爲「Pure」,而通常情況下,Ada函數在純軟件包中更是如此,它是實際上隨時間變化的值的微弱指標,即使是沒有參數的值也是如此。但這是問題或願望的一部分:「常量」≠「只讀」。 – B98

+0

我同意'Volatile'將最有可能禁止不斷傳播。這只是一個想法,我沒有記住LRM。不過,當我這樣做時,我的GNAT發出*警告:常量覆蓋變量*。 – flyx

回答

3

我的建議是,用一個簡單的函數和私有變量:

with Interfaces; 

package Read_Only is 
    subtype Pins is Interfaces.Unsigned_16; 

    function V return Pins; 

private 
    Backing : Pins; 
    function V return Pins is (Backing); 
end Read_Only; 

阿達的調用約定將確保對象是在最有效的方式反正返回。

此外,將其作爲表達式函數實現將確保調用的內聯。

function V return Pins with Inline_Always; 

在這種情況下,呼叫總是被內聯了訪問的變量,所以在條款:如果你想直接暴露和在任何情況下沒有呼叫,甚至當你編譯不優化您也可以使用Inline_Always方面發出的代碼嚴格相當於直接訪問。

編輯:對不起,我剛纔看到你不想要一個函數。鑑於上述,我不明白爲什麼。你能給出一個更精確的理由嗎?

+2

我不認爲表達函數必須內聯。我可以看到,如果它選擇這樣做,它可能會使編譯器更容易。 'Inline_Always'是GNAT中定義的實現。 –

+0

可能的原因包括:讓客戶端控制volatile變量的讀取次數;推遲建立一個完全隱藏變量的接口 - 一個函數將是中間立場,但如果不是「V」的副本類型,可能會引起一個易失性變量的區分,因爲它可能成爲通過引用,所以更多想一想; ......這個需求適用於@SimonWright觀察到的內聯,可能會被視爲模糊,這取決於誰被「阻止」直接查看「V」。 – B98

+0

@SimonWright好點。當他們的身體可見時,Expesssion功能保證內聯。 –

1

有趣的問題。

提供對變量的只讀訪問權限(當然可以通過抽象來實現)。例如,我可以將變量設置爲可調用實體的模式參數或泛型。變量的使用(通過這些常量視圖)將被限制在可調用或泛型實例中。

這個結構不容易添加到現有的程序,我想,因爲程序已經結構化;此外,它不是一個獨立的解決方案,因爲它需要「只讀」和結構之間的耦合。

我不知道有多難的通用會是這樣,但如果你願意重新考慮仿製藥的,我認爲你可以做到這一點的用法:

Generic 
    Type Alpha(<>) is private; 
Package Constant_Access is 
    Type Beta is access constant Alpha; 
    Subtype Gamma is not null Beta; 

    Generic 
     Item_Access : in Gamma; 
    Package Access_Accessor is 
     Item : Constant Alpha renames Item_Access.all; 
     Pragma Volatile(Item); 
    End Access_Accessor; 

End Constant_Access; 

然後,當你需要提供一個只有常量的視圖,你在你的特定類型的實例上使用Access_Accessor的實例 - Constant_Access - 然後,在實例化之後,立即將實例化的Item重命名爲你希望隱藏/建立常量的值的名稱。

是的,這是有點尷尬,但它確實確保你想要的屬性(即可能是揮發性的),即使在面臨重度優化。


編輯:

With 
System.Address_To_Access_Conversions; 

Generic 
    Type Alpha(<>) is private; 
Package Constant_Access with Preelaborate is 

    Package Conversions is new System.Address_To_Access_Conversions(Alpha); 
    Use Conversions, System; 

    ----------------------- 
    -- Type Declarations -- 
    ----------------------- 
    Type Beta is access constant Alpha; 
    Subtype Gamma is not null Beta; 
    Type Epsilon(G : Not Null Access Constant Alpha) is null record 
     with Implicit_Dereference => G, Volatile; 
    -- NOTE: You could excise Beta and Gamma, they are included for flexibility. 

    -------------------------- 
    -- Conversion Functions -- 
    -------------------------- 

    Function "+"(Right : Aliased Alpha) return Gamma is 
     (Right'Access); 
    Function "+"(Right : Gamma) return Alpha is 
     (Right.All); 
    Function "+"(Right : Gamma) return Epsilon is 
     (G => Right.All'Access); 
    Function "+"(Right : Epsilon) return Gamma is 
     (Right.G); 
    Function "+"(Right : Aliased Alpha) return Epsilon is 
     (G => Right'Access); 
    Function "+"(Right : Epsilon) return Alpha is 
     (Right.G.All); -- Not actually needed due to implicit dereferencing. 
    Function "+"(Right : Not Null Access Constant Alpha) return Address is 
     (Right.All'Address); 
    Function "+"(Right : Address) return Alpha is 
     (To_Pointer(Right).All); 
    Function "+"(Right : Epsilon) return Address is 
     (+Right.G); 
    Function "+"(Right : Address) return Epsilon is 
     (G => +To_Pointer(Right).All);  

    ----------------------- 
    -- Accessor Generics -- 
    ----------------------- 
    Generic 
     Item_Access : in Gamma; 
    Package Access_Accessor is 
     Item : Epsilon(Item_Access) 
      with Volatile; 
    End Access_Accessor; 

    Generic 
     Item_Address : in System.Address; 
    Package Address_Accessor is 
     Item : Epsilon := +Item_Address 
      with Volatile; 
    End Address_Accessor; 

End Constant_Access; 
+0

我正在考慮訪問常量,但到目前爲止,並不是關於使用泛型另外!到目前爲止,我仍然無法完成工作。 'Access_Accessor'需要一些調整,因爲**常量**不能是重命名(次要)的一部分,並且'編譯器告訴我'不能將'Volatile'添加到'Item'中。有趣的是,它還指出[RM C.6(13)](http://www.ada-auth.org/standards/aarm12_w_tc1/html/AA-C-6.html#p13)。我目前嘗試使用您的解決方案的[gist](https://gist.github.com/98B/74ce568df4028260a75a8b1bf05cf5ed)。 – B98

+0

@ B98 - 這就是我沒有通過編譯器首先運行它。 無論如何,我已經添加了一個擴展/編輯(並可編譯)的塊,它可以爲您提供所需的所有靈活性。 [嗯,你不能在* Pure *單位中使用它。] – Shark8