MvG*_*MvG 31 c++ gcc g++ static-members constexpr
我想要一个constexpr从constexpr函数计算的值(即编译时常量).我想要将这两个作用于类的命名空间,即静态方法和类的静态成员.
我第一次写这个(对我来说)明显的方式:
class C1 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar = foo(sizeof(int));
};
Run Code Online (Sandbox Code Playgroud)
g++-4.5.3 -std=gnu++0x 对此说:
error: ‘static int C1::foo(int)’ cannot appear in a constant-expression
error: a function call cannot appear in a constant-expression
Run Code Online (Sandbox Code Playgroud)
g++-4.6.3 -std=gnu++0x 抱怨:
error: field initializer is not constant
Run Code Online (Sandbox Code Playgroud)
好吧,我想,也许我必须把事情从课堂上移开.所以我尝试了以下方法:
class C2 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar;
};
constexpr int C2::bar = C2::foo(sizeof(int));
Run Code Online (Sandbox Code Playgroud)
g++-4.5.3将编译,没有投诉.不幸的是,我的其他代码使用了一些基于范围的for循环,所以我必须至少有4.6.现在我仔细观察支持列表,看起来constexpr也需要4.6.随着g++-4.6.3我的到来
3:24: error: constexpr static data member ‘bar’ must have an initializer
5:19: error: redeclaration ‘C2::bar’ differs in ‘constexpr’
3:24: error: from previous declaration ‘C2::bar’
5:19: error: ‘C2::bar’ declared ‘constexpr’ outside its class
5:19: error: declaration of ‘const int C2::bar’ outside of class is not definition [-fpermissive]
Run Code Online (Sandbox Code Playgroud)
这对我来说听起来很奇怪.constexpr这里的事情如何"不同"?我不想添加,-fpermissive因为我更喜欢我的其他代码被严格检查.将foo实现移到类体外部没有明显的效果.
有人能解释一下这里发生了什么吗?我怎样才能实现我的目标?我主要对以下几种答案感兴趣:
其他有用的答案也是受欢迎的,但也许不会轻易接受.
Ben*_*igt 19
标准要求(第9.4.2节):
甲
static文字类型的数据成员可以在类定义与声明constexpr说明符; 如果是这样,它的声明应指定一个大括号或等于初始化器,其中作为赋值表达式的每个initializer子句都是一个常量表达式.
在你的"第二次尝试"和Ilya的答案中的代码中,声明没有括号或等于初始化器.
你的第一个代码是正确的.不幸的是gcc 4.6不接受它,我不知道在哪里方便地尝试4.7.x(例如,ideone.com仍然停留在gcc 4.5上).
这是不可能的,因为遗憾的是,标准排除了constexpr在类完成的任何上下文中初始化静态数据成员.9.2p2中的括号或等于初始化程序的特殊规则仅适用于非静态数据成员,但这一个是静态的.
最可能的原因是constexpr变量必须作为成员函数体内部的编译时常量表达式提供,因此变量初始值设定项在函数体之前完全定义 - 这意味着函数仍然不完整(未定义)在初始化程序的上下文中,然后此规则启动,使表达式不是常量表达式:
在
constexpr函数或constexpr构造函数的定义之外调用未定义的函数或未定义的构造constexpr函数constexpr;
考虑:
class C1
{
constexpr static int foo(int x) { return x + bar; }
constexpr static int bar = foo(sizeof(int));
};
Run Code Online (Sandbox Code Playgroud)
小智 5
1)Ilya的示例应该是无效的代码,这是因为以下事实:静态constexpr数据成员栏违反了标准中的以下声明而被离线初始化:
9.4.2 [class.static.data] p3:...可以使用constexpr说明符在类定义中声明文字类型的静态数据成员;如果是这样,则其声明应指定大括号或相等的初始化程序,其中每个作为赋值表达式的初始化程序子句都是一个常量表达式。
2)MvG问题中的代码:
class C1 {
constexpr static int foo(int x) { return x + 1; }
constexpr static int bar = foo(sizeof(int));
};
Run Code Online (Sandbox Code Playgroud)
就我所见,它是有效的,并且直觉上可以预期它会起作用,因为静态成员foo(int)是由bar开始处理的时间定义的(假设自上而下进行处理)。一些事实:
在constexpr函数或constexpr构造函数的定义之外调用未定义的constexpr函数或未定义的constexpr构造函数;
class C1
{
constexpr static int foo() { return bar; }
constexpr static int bar = foo();
};
Run Code Online (Sandbox Code Playgroud)
看起来是无效的,但由于不同的原因,不仅仅是因为在bar的初始化器中调用了foo。逻辑如下:
但在(5.19 p2)中的项目符号9中,由于尚未初始化,该小节 未满足:
- 左值到右值转换(4.1),除非将其应用于:
- 整数或枚举类型的glvalue,该值引用具有常量初始化的,具有先前初始化的非易失性const对象。
因此,bar的左值到右值转换不会产生未满足(9.4.2 p3)中要求的常数表达式。
带有参数的constexpr函数的调用,当被函数调用替换(7.1.5)替换时,不产生常量表达式
| 归档时间: |
|
| 查看次数: |
28246 次 |
| 最近记录: |