2015-12-14 115 views
7

例如下面的代碼不編譯除非incr()被聲明constexpr在C++ 14標準中,它是否說非constexpr函數不能用於constexpr函數的定義?

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo() { 
    int n = 0; 
    incr(n); 
    return n; 
} 

在C++ 14在§7.1.5/ 3尋找我們有:

的定義constexpr函數應該滿足以下約束:
(3.1) - 它不應該是虛擬的(10.3);
(3.2) - 它的返回類型應該是一個文字類型;
(3.3) - 它的每個參數類型應該是一個文字類型;
(3.4) - 其功能體應爲=刪除,=默認情況下,或不包含

(3.4.1)的化合物語句 - 一個ASM清晰度,
(3.4.2) - goto語句,
(3.4.3) - 一個try-block,或者
(3.4.4) - 一個變量的定義非文字類型或靜態或線程存儲持續時間或其中 無初始化被執行。

+0

也許值得指出的[前面的問題](http://stackoverflow.com/q/34211688/1708801),其覆蓋了許多相同的地,儘管從不同的角度。 –

+0

@ShafikYaghmour我真的很感激你對這個新問題的評論。 – Ayrosa

+0

請注意,你所引用的內容是必要的*但不是充分*的條件,即如果這些條件被違反,那麼代碼是不合格的,但是如果他們沒有違反,那麼代碼可能會或可能不會是正確的,我們必須查看規範的其他部分。 –

回答

10

兩段後,在[dcl.constexpr]/5:

對於非模板,非缺省constexpr功能或非模板,非默認,非繼承 constexpr構造函數,如果不存在任何參數值,以便函數或構造函數的調用可以是核心常量表達式(5.20)的評估子表達式,或者對於某個對象(3.6.2)的構造函數,常量 初始值設定項, ,該方案是不健全的;不需要診斷。

無參數存在,使得foo()可以是芯常量表達式由於incr(),因此程序是形成不良的(NDR)。

+0

我不認爲§7.1.5/ 5與這個問題無關。例如,在標準中,它是否表示constexpr函數的主體必須是核心常量表達式? – Ayrosa

+0

@Ayrosa:就在那裏。 「函數或構造函數的調用可以是核心常量表達式的一個評估子表達式」但它不是必須的整個身體,只是評估的部分。 –

+0

@BenVoigt但是,它並沒有說constexpr函數的主體是核心常量表達式。 – Ayrosa

4

它沒有。

下是允許的,即使它你猜測什麼是被禁止的:

int incr(int& n) { 
    return ++n; 
} 

constexpr int foo(bool x) { 
    int n = 0; 
    if (x) incr(n); 
    return n; 
} 

在你的問題中的代碼是通過與巴里的規則不允許援引他的回答。但是在我的變體中,確實存在一組參數(具體地說,false),調用foo會導致編譯時常量表達式。

請注意,診斷不是必需的 - 符合的編譯器也可以允許您的版本進行編譯。

+1

值得注意的是,g ++無法編譯兩個版本,在這兩種情況下給出相同(不正確)的錯誤消息。鏗鏘++彙編這一個,並拒絕原始的,引用正確的原因:「constexpr函數永遠不會產生一個常量表達式」。 –

+1

@ n.m。這個bug在gcc中已經修復 – bames53

+0

我花了一段時間才真正體會到了答案,你的和bames53的(+1)的質量。 – Ayrosa

8

什麼你要找的是§5.19:

一個條件表達式Ë是一個核心的常量表達式,除非Ë的評價,以下抽象機的規則( 1。9)將評估以下表達式之一:

這適用於對函數調用constexpr表達式的評估。也就是說,調用constexpr函數將是一個'核心常量表達式',如果評估函數,即根據C++抽象機器的規則執行函數主體,則不會執行給定列表中禁止的任何事情在第5.19節中。

一個列表中的項目是:

  • 功能比[...]一個constexpr功能以外的調用

所以申請到您的示例:評估表達式foo()評估對函數incr()的調用,該函數不是constexpr函數,這意味着表達式foo()不是核心常量表達式。此外,由於上述適用於函數foo的所有可能調用,第7.1.5節/5.5節中的規則開始,並且意味着您的示例程序不合格,不需要診斷,即使您從不使用實際上撥打foo()


由於本福格特指出一個constexpr函數可以包含非consexpr函數的調用,只要函數的具體評價實際上並不評價任何這樣的函數調用(或它出現在,做一個上下文不需要一個常量表達式)。

5.19中的限制僅與表達式評估的一部分實際上最終被評估的表達式有關。

例如:

#include <iostream> 

int incr(int &n) { return ++n; } 

enum E {be_constexpr, not_constexpr}; 

constexpr int foo(E e = be_constexpr) { 
    int n = 0; 
    if (e == not_constexpr) { incr(n); } 
    return n; 
} 

int main() { 
    constexpr int a = foo(); // foo() is a constant expression 
    int b = foo(not_constexpr); // may or may not evaluate `foo(non_constexpr)` at runtime. In practice modern C++ compilers will do compile-time evaluation here even though they aren't required to. 
    // constexpr int c = foo(not_constexpr); // Compile error because foo(not_constexpr) is not formally a constant expression, even though modern compilers can evaluate it at compile-time. 

    std::cout << a << ' ' << b << '\n'; 
} 
+0

我花了一段時間才真正體會到你的答案和本Voigt(+1)的質量。 – Ayrosa

相關問題