IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 记C++中静态常量数据成员在不同标准下的一些区别 -> 正文阅读

[C++知识库]记C++中静态常量数据成员在不同标准下的一些区别

Note: 在C++中,class类型的静态常量数据成员分为两种:static const的和static constexpr的。

Note: 不同编译器对C++标准的支持程度不一样,在某个编译器上执行没问题不代表它一定符合了C++标准。


若整型或枚举类型的静态数据成员被声明为 const(且非 volatile ),则它能以身为常量表达式的类内初始值,直接在类定义内初始化,这不是必须的,也可以在类外初始化

struct X
{
    const static int n = 1;
    static const int m{2}; 	// C++11 起
    const static int k;		// 在类外初始化
};
const int X::k = 3;

C++11起,若将字面类型 (LiteralType) 的静态数据成员声明为 constexpr,则它必须以每个表达式均为常量表达式的类内初始值,直接在类定义内初始化

struct X {
    constexpr static int arr[] = { 1, 2, 3 };        // OK
    constexpr static std::complex<double> n = {1,2}; // OK
    constexpr static int k; // 错误:constexpr 静态数据成员要求类内初始化
};

ODR式 使用

对象被 ODR 式使用: 读取(除非它是编译时常量)或写入对象的值,取对象的地址,或将引用绑定到它;
引用被 ODR 式使用: 引用有被使用,且其所引用者在编译时未知;
函数被 ODR 式使用: 调用函数或取其地址。

C++11前
const 静态数据成员被 ODR 式使用,则仍需要在 命名空间作用域(即全局作用域)处 定义,但它不能在全局作用域中重复初始化。

struct X {
    static const int n = 1;		// 声明
};
const int *p = &X::n; 	// X::n 被 ODR 式使用
const int X::n;       	// 定义并使用类内初始值初始化

C++11起,C++17前
const 静态数据成员或 constexpr 静态数据成员被 ODR 式使用,则仍需要在命名空间作用域(即全局作用域)处定义,但它不能重复初始化。

struct X {
    static const int n = 1;		// 声明
    static constexpr int m = 4;	// 声明
};
const int *p = &X::n, *q = &X::m; 	// X::n 与 X::m 被 ODR 式使用
const int X::n;       				// 定义并使用类内初始值初始化
constexpr int X::m;         		// 在C++11~C++17中,这是一个定义

C++17起
const (且非 inline )静态数据成员被 ODR 式使用,则仍需要在命名空间作用域(即全局作用域)处定义,但它不能重复初始化。
constexpr 静态数据成员无论有没有被 ODR 式使用,都不需要在全局作用域处再次定义。当然可以在全局作用域处提供“定义”,尽管这是冗余的
若静态数据成员被声明为 constexpr ,则它隐式 inline 且不需要在命名空间作用域进行重声明。虽然这种无初始化值的重声明(之前则为必要,如上所示)仍然得到容许,但已被弃用。

struct X {
    static const int n = 1;		// 声明
    static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; 	// X::n 与 X::m 被 ODR 式使用
const int X::n;       				// 一直都必须要定义
constexpr int X::m;         		// C++17 中的 X::m 不需要,可以注释掉

为了解答C++17起,关于`constexpr` 静态数据成员在全局作用域定义,为什么是冗余的?我们通过以下C++代码和汇编代码进行比较。

Note: 下面使用了支持C++17标准的GCC编译器、支持C++11标准的GCC编译器进行对比。因为gcc对C++标准的支持更全面。

例子一:

struct S {
	static constexpr int x = 42;
};
constexpr int S::x;

在这里插入图片描述
在这里插入图片描述

例子二:

struct S {
	static constexpr int x = 42;
};
//constexpr int S::x;

在这里插入图片描述
在这里插入图片描述

例子三:

struct S {
	static constexpr int x = 42;
};
//constexpr int S::x;
const int &AA = S::x;	// X::m 被 odr 式使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在例子二中:
编译器看到X::m没有被 odr-used ,也没有显式定义,就做了一个小小的优化,不给这个常量固定分配空间了。但是它一旦被 odr-used ,编译器仍然会分配空间,就像例子三一样。
分配空间也会标为 weak_definition,像这样的多个定义最终会只取一个。

在例子三中:
可以看出在C++17标准下的constexpr 静态数据成员哪怕没有在全局作用域再次定义,编译器也会给其分配内存空间并初始化。相反的是在C++11标准下的constexpr 静态数据成员如果没有在全局作用域再次定义,编译器就不会给其分配内存空间并初始化,并在它被 odr-used 时报错:undefined reference to S::x

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-29 22:54:07  更:2022-01-29 22:54:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:00:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码