[英]can have definition variable of non-literal type in constexpr function body c++14?
[英]Where in C++14 Standard does it say that a non-constexpr function cannot be used in a definition of a constexpr function?
例如,除非將incr()
聲明為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) - 其函數體應為= delete,= default或不包含的復合語句(3.4.1) - asm-definition,
(3.4.2) - goto語句,
(3.4.3) - 試塊,或
(3.4.4) - 非文字類型或靜態或線程存儲持續時間的變量的定義,或者不執行初始化的定義。
兩段之后,在[dcl.constexpr] / 5中:
對於非模板,非默認的
constexpr
函數或非模板,非默認的,非繼承的constexpr構造函數,如果不存在參數值,則調用函數或構造函數可以是核心常量的計算子表達式表達式(5.20),或者,對於構造函數,某個對象(3.6.2)的常量初始值設定項,程序是不正確的; 無需診斷。
由於incr()
,因為foo()
可能是核心常量表達式,所以不存在任何參數,因此程序是錯誤的(NDR)。
你要找的是§5.19:
條件表達式 e是核心常量表達式,除非根據抽象機器(1.9)的規則評估e將評估以下表達式之一:
這適用於對constexpr
函數調用的表達式的求值。 也就是說,調用constexpr
函數將是一個'核心常量表達式',如果評估函數,即根據C ++抽象機器的規則執行函數體,則不執行給定列表中禁止的任何事情在第5.19節中。
列表中的一項是:
- 調用constexpr函數以外的函數
因此,將此應用於您的示例:計算表達式foo()
計算對函數incr()
的調用,該函數不是constexpr函數,這意味着表達式foo()
不是核心常量表達式。
此外,由於上述情況適用於函數foo
所有可能調用,因此第7.1.5 / 5節中的規則啟動並意味着您的示例程序格式錯誤,無需診斷,即使您實際上從未調用foo()
。
正如Ben Voigt所指出的,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';
}
它沒有。
允許以下內容,即使它完全符合您的猜測是禁止的:
int incr(int& n) {
return ++n;
}
constexpr int foo(bool x) {
int n = 0;
if (x) incr(n);
return n;
}
在他的回答中引用了巴里的規則,你的問題中的代碼是不允許的。 但在我的變體中,確實存在一組參數(特別是false
), foo
調用會導致編譯時常量表達式。
請注意,不需要診斷 - 符合標准的編譯器也可以允許您的版本進行編譯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.