2012-02-08 58 views

回答

55

tl; dr:constexpr由於語言規範中存在缺陷,C++ 11中的圖靈並不完整,但該錯誤已在標準的後續草稿中得到解決,並且clang已經實現了該修復。按照ISO C++ 11國際標準的規定,

constexpr不是圖靈完備的。草圖證明:

  • constexpr功能f的結果(或非終止)上的參數,a...的特定順序,僅受a...
  • 可以內部構造的每一個參數值的值確定的的常量表達式必須是文字型,其通過[basic.types]p10是任一的:
    • 標量類型,
    • 參考,
    • 文本類型的陣列,或
    • 類類型
  • 每個上述情況下具有有限的一組值。
    • 對於一個標量非指針類型,這個細微之處。
    • 對於要在常量表達式中使用的指針或引用,它必須由地址或引用常量表達式初始化,因此必須引用靜態存儲持續時間的對象,其中任何程序中只有有限數量的對象。
    • 對於一個數組,bound必須是一個常量,並且每個成員都必須由一個常量表達式進行初始化,結果如下。
    • 對於類類型,成員數量有限,並且每個成員都必須是文字類型,並由常量表達式進行初始化,結果如下。
  • 因此,這可以f接收該組可能的輸入a...是有限的,因此,任何有限描述constexpr系統是一個有限狀態機,並因此不是圖靈完整。

但是,自從C++ 11標準發佈以來,情況發生了變化。

Johannes Schaub對std::max() and std::min() not constexpr的回答中描述的問題已作爲核心問題1454向C++標準化委員會報告。在2012年2月的WG21會議上,我們確定這是標準中的缺陷,並且所選分辨率包括能力使用指定臨時對象的指針或引用成員創建類類型的值。這允許無限量的信息被constexpr函數累積和處理,並且足以使constexpr評估圖靈完成(假設該實現支持遞歸到無限深度)。

爲了證明constexpr圖靈完備性爲實現核心問題1454的建議的決議編譯器,我寫了圖靈機模擬器鐺的測試套件:

http://llvm.org/svn/llvm-project/cfe/trunk/test/SemaCXX/constexpr-turing.cpp

幹線版本g ++和clang都實現了這個核心問題的解決方案,但是g ++的實現目前無法處理這些代碼。

+1

有趣!如果我的理解正確,這個區別取決於一個事實,即一個程序只能有有限數量的靜態存儲持續時間的對象,但它可能有無限數量的臨時對象。你能解釋爲什麼嗎? – HighCommander4 2012-03-02 08:34:05

+3

@ HighCommander4靜態存儲持續時間的每個對象由源代碼中的聲明引入(其中只有有限數量,並且每個對象只引入有限數量的可單獨尋址的對象),而無界遞歸可引入無限數量的臨時工。這個觀點僅適用於C++抽象機器 - 每一個真正的實現最終都會遇到某種形式的資源限制,所以仍然有一些有限的(但通常是未知的)限制。 – 2012-03-05 07:57:08

+2

非常抽象:-) – 2013-09-28 23:22:02

7
+1

+1:OMG現在我明白了他們在GoingNative會議小組OOU中所討論的constexpr帶來了什麼新的瘋狂/迷人; – Klaim 2012-02-09 01:49:09

+0

字符串解析是翻譯時計算變得美麗的地方。 – ex0du5 2012-02-09 21:05:09

+6

能夠讀取字符串文字並不意味着它是圖靈完整的(例如,它不演示如何在無限(而不是半無限)磁帶上寫入)。 – kennytm 2012-02-10 12:50:41

1

如果我們在現實的計算機帳戶的限制 - 如有限內存和MAX_INT的有限值 - 然後,當然,constexpr(也整個C++)不是圖靈完整的。但是如果我們將刪除這個限制 - 例如,如果我們將int看作一個完全任意的正整數 - 那麼是的,C++的constexpr部分將是Turing完整的。很容易表達任何部分遞歸函數。 (n)= n + 1和選擇器I_n^m(x_1,...,x_n)= x_m,明顯的疊加可以用constexpr表示。

原始遞歸可以做它筆直的路:

constexpr int h(int x1, ..., int xn, int y) { 
    return (xn == 0) ? f(x1, ..., xn) : g(x1, ..., xn, y-1, h(x1, ..., xn, y-1)); 
} 

而對於部分遞歸我們需要一個簡單的一招:

constexpr int h(int x1, ... int xn, int y = 0) { 
    return (f(x1, ... xn, y) == 0) ? y : h(x1, ..., xn, y+1); 
} 

所以我們得到任何部分遞歸函數爲constexpr。