假设我有一个可以通过constexpr函数返回常量表达式的类:
template<int N>
struct Foo {
constexpr int Bar() const { return N; }
};
Run Code Online (Sandbox Code Playgroud)
如果我想初始化constexpr值Foo::Bar(),我应该如何传递类型的参数Foo?我已经尝试了这两个,constexpr每个都有一个示例变量来测试它是否可以初始化:
template<int N>
constexpr int ByValue(Foo<N> f) {
constexpr int i = f.Bar();
return f.Bar();
}
template<int N>
constexpr int ByReference(const Foo<N> &f) {
constexpr int i = f.Bar();
return f.Bar();
}
constexpr int a = ByValue(Foo<1>{});
constexpr int b = ByReference(Foo<1>{});
Run Code Online (Sandbox Code Playgroud)
但是clang 3.7引发了一个错误,ByReference而gcc> = 5.1则没有:现场演示
main.cpp:15:25: error: constexpr variable 'i' must be initialized …Run Code Online (Sandbox Code Playgroud) constexpr int func(int const& rf){
return rf;
}
int main(){
constexpr int value = func(0);
}
Run Code Online (Sandbox Code Playgroud)
考虑上面的代码,变量value应该由一个常量表达式初始化,即func(0),它首先应该是一个核心常量表达式。为了判断表达式是否func(0)是核心常量表达式,将应用以下规则,即:
expr.const#2.7
表达式 e 是核心常量表达式,除非对 e 的求值遵循抽象机的规则,将求值以下表达式之一:
左值到右值的转换,除非它应用于
[...], 或者
(2.7.4) 文字类型的非易失性泛左值,指的是其生命周期开始于 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之前rf,应该评估 glvaluerf以确定对象的身份,该身份由以下规则决定:
左值是一个表达式,其计算确定对象、位域或函数的标识。
这意味着不仅应遵守项目符号 [expr.const#2.7],还应遵守 [expr.const#2.11]。
因为 id-expressionrf是引用类型。因此,为了使表达式func(0)成为核心常量表达式,id-表达式rf必须有一个前置的初始化 …
core constant expression在C++ 11标准(N3690)的最新草案中有11个对表达式的引用,它们都没有定义这个实体是什么.
人们还可以发现这里的表达式core constant expression定义很好,基本上与标准用于定义表达式的术语相同.conditional-expression
因此,我想在这个问题上获得一些意见,在我看来,这个问题在标准中是错误的.
现在,假设cppreference中的定义是正确的,我还想知道为什么下面的代码片段在Coliru和Ideone中编译,尽管在提到的定义中有第(10)项?
#include <iostream>
int main()
{
const double x = 2.;
constexpr double y = x;
std::cout << y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我特别考虑表达式中lvalue to rvalue implicit conversion的变量,而上述第(10)项中的任何条款(a),(b)和(c)都没有涵盖这一点.xconstexpr double y = x;
谢谢您的帮助.