constexpr int func(int const& rf){
return rf;
}
int main(){
constexpr int value = func(0);
}
考虑上面的代码,该变量value
应由一个常量表达式初始化,该常量表达式func(0)
首先应为核心常量表达式。若要确定该表达式func(0)
是否为核心常量表达式,将对其应用以下规则,即:
expr.const#2.7
表达式e是核心常量表达式,除非按照抽象机的规则对e求值将对以下表达式之一求值:
左值到右值的转换,除非将其应用于
[...], 要么
(2.7.4)文字类型的非易失性glvalue,指的是在e的求值内开始寿命的非易失性对象;
尽管已将lvalue-to-rvalue conversion
应用于rf
且这种转换满足项目符号(2.7.4)的要求,但是请看下一段,即:
expr.const#2.11
引用引用类型的变量或数据成员的id表达式,除非引用具有先前的初始化且
- (2.11.1)使用常量表达式对其进行初始化,或者
- (2.11.2)其寿命始于e的评估;
我不知道这句话到底是什么preceding initialization
意思?这是否意味着在使用变量之前应先对其进行初始化,或者意味着在变量的声明中应具有初始化程序。无论如何,在将lvalue-to-rvalue conversion
glvalue应用于glvalue之前rf
,rf
应先评估glvalue以确定对象的身份,这取决于:
glvalue是一个表达式,其求值确定对象,位字段或函数的身份。
这意味着不仅要遵守子弹[expr.const#2.7],而且还要遵守[expr.const#2.11]。
因为id-expressionrf
是引用类型。因此,为了使表达式func(0)
成为核心常量表达式,id表达式rf
必须具有前面的初始化,并且至少满足项目符号(2.11.1)和(2.11.2)中的一个。在我的示例中,服从项目符号(2.11.2)rf
,编译器同意这func(0)
是一个常量表达式。结果就在这里,结果似乎证明这preceding initialization
意味着be initialized
在第一个示例中由于参数声明而不是拥有初始化器,而不是拥有初始化器。
为了检查这种想法,我测试以下代码:
constexpr int func(int const& rf){
constexpr int const& v = rf;
return 0;
}
int main(){
static int const data = 0;
constexpr int value = func(data);
}
编译器的结果指出,rf
它不是一个常量表达式。我对这个结果感到困惑。根据以上假设。rf
有一个先前的初始化,并且即使是子弹不满足,也要(2.11.1)
遵守它,因为它data
是一个常量表达式(2.11.2)
。
因此,我想知道该短语的实际preceding initialization
含义是什么?如果这意味着变量的声明具有初始化程序,那么func(0)
第一个示例中的表达式如何成为常量表达式?
结果似乎证明“在先初始化”意味着“被初始化”而不是具有初始化程序,因为在第一个示例中,参数声明没有初始化程序。
它的确表示“已初始化”,但是更重要的是要在要求值的表达式的上下文中进行先前初始化的可见性。在您的示例中,在评估上下文中,编译器具有上下文以查看with的初始化。然而,在评价只是表达的范围内,它不看的初始化。该分析是本地的,因为它不会分析每个呼叫站点。这导致表达式本身不是常量表达式,而是常量表达式。func(0)
rf
0
rf
func
rf
rf
func
func(0)
如果您要编写此代码:
constexpr int func(int const& rf) {
/* constexpr */ int const& v = rf;
return v;
}
int main() {
static int const data = 0;
constexpr int value = func(data);
}
这是一次好,因为在的情况下func(data)
,rf
有一个常量表达式前面的初始化data
,并v
具有前面的初始化与rf
它是不是一个常量表达式,但其生命周期开始的评价中func(data)
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句