constexpr静态成员变量的异常行为
Strange behavior with constexpr static member variable
这是对静态constexpr char[]的未定义引用的后续问题。
以下程序构建并运行良好。
#include <iostream>
struct A {
constexpr static char dict[] = "test";
void print() {
std::cout << A::dict[0] << std::endl;
}
};
int main() {
A a;
a.print();
return 0;
}
但是,如果我将A::print()
更改为:
void print() {
std::cout << A::dict << std::endl;
}
我在g++4.8.2中得到以下链接器错误。
/tmp/cczmF84A.o:在函数"A::print()"中:socc.cc:(.text._ZN1A5printEv[_ZN1A5 printEv]+0xd):对"A::dict"的未定义引用collect2:错误:ld返回1退出状态
链接器错误可以通过添加一行来解决:
constexpr char A::dict[];
在类定义之外。
但是,我不清楚为什么使用数组的一个成员不会导致链接器错误,而使用数组会导致链接器出错。
该标准不要求对故障进行任何诊断,以便在需要定义的地方提供定义。
3.2一个定义规则[basic.def.odr]
4每个程序应包含该程序中使用的每个非内联函数或变量的一个定义;无需诊断。[…]
这意味着实现可以优化对此类变量的访问,这就是GCC的第一个案例中发生的情况。
GCC和clang都决定,他们更喜欢一致的用户体验,其中关于缺少定义的错误消息不取决于优化级别。通常,这意味着任何缺少的定义都会导致一条错误消息。然而,在这种情况下,GCC即使在-O0
也在进行一些最小的优化,从而避免了错误。
但无论哪种方式,该程序都是错误的,因为即使是A::dict[0]
也是ODR使用:
3.2一个定义规则[basic.def.odr]
3名称显示为潜在求值表达式
ex
的变量x
由ex
使用,除非将左值到右值转换(4.1)应用于x
产生不调用任何非平凡函数的常量表达式(5.19),并且如果x
是对象,则ex
是表达式e
的潜在结果集的元素,其中左值到右值的转换(4.1)应用于e
,或者e
是丢弃的值表达式(第5条)。[…]
A::dict
的使用不涉及左值到右值的转换,它涉及数组到指针的转换,因此该异常不适用。
除了@hvd在他的回答中提供的信息。。。
来自C++标准草案N3337(强调矿):
9.4.2静态数据成员
3如果非易失性
const static
数据成员是整型或枚举型,则其在类定义中的声明可以指定大括号或相等初始化器,其中作为赋值-表达式的每个初始化器子句都是常量表达式(5.19)。文本类型的static
数据成员可以在类定义中将constexpr
说明符声明;如果是,则其声明应指定大括号或相等的初始值设定项,其中作为赋值表达式的每个初始值设定子句都是常量表达式。[注意:在这两种情况下,成员都可能出现在常量表达式中。--结束注释]如果在程序中使用odr(3.2),则成员仍应在命名空间范围中定义,并且命名空间范围定义不应包含初始值设定项
假定A::data
是表达式A::data[0]
中使用的odr,根据标准,它应该在名称空间范围中定义。g++能够成功创建一个程序,而不需要在名称空间范围中定义A::data
,这一事实并不能使程序正确。为了符合标准,应定义A::data
。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 如何在C++中使用非静态成员函数作为回调函数
- (C++)为什么静态成员可以在初始化之前使用
- 类的全局对象和静态成员
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- 模板化类中静态成员的延迟初始化
- 使用静态成员声明类时遇到问题
- C++:是否可以使用非静态成员变量模板?
- 静态成员函数使用相同的名称时出现模板类型名称错误
- 如何在复杂继承中访问静态成员变量
- 在 nullptr 上调用无状态类的非静态成员函数是否合法?
- 如何在友元函数中使用静态成员而不添加前缀 [类名]::
- C++构造函数和静态成员
- 为什么传递非静态成员函数会导致编译错误?
- 非静态成员失败的线程调用函数
- 静态成员变量不会由 gettext 转换
- decltype:使用指针访问类的静态成员
- 处理类内的回调时,必须调用对非静态成员函数的引用
- constexpr静态成员变量的异常行为
- 静态成员回收内存并从异常中恢复