Visual Studio 2015 RTM附带对的支持 常量表达式 如C++ 11语言标准中规定的。这个版本从我们的用户和C++社区收到了很多优秀的反馈。使用这个反馈,我们一直在努力改进VS 2015更新1的实现。我们的目标是VS 2015更新1,完成C++ 11 CONTXEPR的最后一个显著特征工作,并提高我们的实现的健壮性。这篇博文将提供一些注释来解释VS2015更新1将我们置于何处 以及我们在constexpr支持下的发展方向。
静态初始值设定项
VS 2015附带了一个警告,指出编译器可以检测并使用初始值设定项进行constexpr求值,但不会静态地发出这些初始值设定项。也就是说,虽然编译器有足够的信息来发出完全实例化的类型,这些类型可以从已编译的可执行文件加载,但它没有发出完全实例化的类型。这些类型在运行时被实例化并构造,因为大多数C++对象传统上是这样的。
好消息是VS 2015 Update 1现在支持发射静态初始值设定项!这些类型在加载到内存时会被完全实例化,而不是在运行时运行代码来初始化它们。这是我们需要为C++ 11 CONTHEXPR支持实现的最后一个特性,我们很高兴能用更新1来传送它。
我们应该感谢Tanveer Gani所做的巨大工作,使这个特性与Update 1一起发布。由于他的工作,Update 1将在发布时完全支持为constexpr对象发出静态初始化器。它也将用部分支持来支持具有CONTXPR构造函数的非文字类型对象的不断初始化(如C++语言标准的3.3.2节中所指定的)。具体来说,带有虚拟函数的类型还没有实现。
静态初始化器是实现 std::onceU标志 ,用于 std::给你打一次电话 . 斯蒂芬在他的电话里说 博客文章 关于VS 2015 RTM中STL的改进。
VS 2015 Update 1为运行时执行生成的代码的减少可能非常显著。我想用一些例子来探讨一下这种行为。首先显示C++源,然后是说明静态初始化的汇编代码。这些代码段的程序集是通过调用C++编译器生成的。 /财务会计准则委员会 旗帜。
示例1:Constexpr对象的初始化
我们将从一个简单的示例开始—使用constexpr构造函数构造一个类型的简单实例。
结构 点{ 常量表达式 点(int x1,int y1) :x(x1),y(y1) {}
整数x; 内景; }; 常量表达式 点p1(10,11);
第一, 这个 VS 2015 RTM生成的组件 对于此代码段(用于比较):
; VS 2015 RTM asm 公共??0点@@QEAA@HH@Z ; 点::点 _BSS公司 段 ?p1@@3UPoint@@B DQ 01H重复(?) ; 第1页 _BSS公司 末端 文本$di 段 ??uu Ep1@@YAXXZ程序 ; `“p1”的动态初始值设定项,COMDAT
; 8 : constexpr点p1(10,11);
附属的 rsp,40号 ; 00000028小时 压敏电阻 r8d,11号 压敏电阻 edx,10倍 利亚 rcx,平偏移:?p1@@3UPoint@@B 呼叫 ??0点@@QEAA@HH@Z ; 点::点 添加 rsp,40号 ; 00000028小时 雷特 0 ??uu Ep1@@YAXXZ ENDP ; `“p1”的动态初始值设定项 文本$di 末端
现在VS 2015 Update 1生成的程序集:
; VS 2015更新1 asm 常数 段 ?p1@@3上点@@B DD公司 0啊 ; 第1页 DD公司 0bH公司 常数 末端
请注意,VS 2015更新1中生成的程序集中没有初始化代码。在VS 2015更新1中运行VisualStudio调试器下的C++代码将不会执行针对点的构造函数。
示例2:Constexpr对象数组的初始化
继续上面点的定义,我们将创建一个点数组:
常量表达式 点arr[]={点(2,3),点(5,7),点(11,13)};
VS 2015 Update 1生成的程序集非常出色:
; VS 2015更新1 asm 常数 段 ?排列@@3QBUPoint@@B DD公司 02小时 ; 阿里尔 DD公司 03小时 DD公司 05小时 DD公司 07小时 DD公司 0bH公司 DD公司 0小时 常数 末端
示例3:初始化constexpr对象的指针和引用成员
此代码段使用指向全局constexpr变量的指针和引用初始化constexpr对象。
constexpr int I = 42;struct A { const int& ref; const char *ptr; const char *&ref2; constexpr A(const char *p, const int& r) : ref(r), ptr(p), ref2{ptr} {}};constexpr A a{ "qwerty", I };
此示例实际上在VS 2015 RTM中导致结冰,但会生成 在VS 2015更新1中令人愉快的简洁汇编代码。
; VS 2015更新1 asm 常数 段 ?我@@3HB DD公司 02安培 ?a@@@3UA@@@B DD公司 平坦:?I@@3HB ; 一 DD公司 单位:2668新加坡元 DD公司 平坦:?a@@3UA@@B+4 2668新元 分贝 ‘qwerty’,00小时 常数 末端
示例4:使用基构造函数初始化constexpr类
即使是具有复杂(非虚拟)继承的类也可以静态初始化。我不打算列出VS 2015 RTM,因为它太长了,但是您可以通过使用 /财务会计准则委员会 旗帜。
结构 空{}; 结构 A{ 短i; 常量表达式 A(内景ii) :一(二) {} }; 结构 B类{ 双d; 常量表达式 B(双di) :d(di) {} }; 结构 空的,A,B{ 双x; 常量表达式 C() :x(1.0)、A(42)、B(-1.0) {} }; 常量表达式 C、C;
以及VS 2015 Update 1生成的程序集:
; VS 2015 Update 1 asmCONST SEGMENT?c@@3UC@@B DW 02aH ; c ORG $+6 DQ 0bff0000000000000r ; -1 DQ 03ff0000000000000r ; 1CONST ENDS
示例5:初始化非文本类型
如上所述,一些用常量初始化的非文本类型可以静态初始化。在下面的示例中,提供给constexpr构造函数的initialized是一个常量,因此update1可以静态初始化它。请注意,该类型有一个析构函数,它使该类型成为非文本类型。
extern "C" int puts(const char*);
struct NonLiteralType {
const char *p;
constexpr NonLiteralType(const char *pp)
: p(pp)
{}
~NonLiteralType() {
puts("~NonLiteralType()");
}
};
NonLiteralType nlt("qwerty");
int main(){}
更新1中生成的程序集未将对象放置在CONST段中,因为它未声明为constexpr:
; VS 2015更新1 asm 常数 段 2669新加坡元 分贝 ‘qwerty’,00小时 常数 末端
_数据 段 ?nlt@@3UNonLiteralType@@A DD公寓:$SG2669 ; nlt公司 _数据 末端
使用注册的“atexit”函数销毁非文字类型对象:
; VS 2015更新1 asm CRT$XCU 段 ?nlt$初始值设定项$@@3P6AXXZA DD扁平:??u Fnlt@@YAXXZ ; nlt$初始值设定项$ CRT$XCU 末端 常数 段
文本$yd段 ??uufnlt@@YAXXZ 过程 ; `“nlt”的动态atexit析构函数,COMDAT 推 ebp公司 压敏电阻 ebp,特别是 压敏电阻 ecx,偏移量?nlt@@3UNonLiteralType@@A ; nlt公司 呼叫 ??1非文字类型@@QAE@XZ ; 非文字类型::~非文字类型 流行音乐 ebp公司 雷特 0 ??uu Fnlt@@YAXXZ ENDP`“nlt”的动态atexit析构函数 文本$yd结束
质量改进
除了静态初始化工作之外,我们还修复了约45个与constexpr用法相关的bug。这些缺陷大部分是客户向我们报告的。因为我们试图区分客户问题的优先级,所以在编写constexpr代码时,您应该看到全面的改进,而不是在任何特定领域。下表显示了我们修复的bug。多亏了所有的虫子!
职务 | 连接客户 | 康涅狄格州 |
[constexpr]对成员变量的类使用final将中断constexpr | 阿帕雷 | 1135313 |
创建constexpr std::array时出现错误C2131 | 安德烈·阿什赫敏 | 1574634 |
constexpr void指针变量未被视为常量 | 花青素1 | 1609590 |
std::array的constexpr失败 | 布兰登肯特尔 | 1604956 |
Constexpr导致内部编译器错误 | camhusmj38型 | 1573435 |
Constexpr导致内部编译器错误 | camhusmj38型 | 1570534 |
Constexpr产生错误的结果[与LLVM相比] | camhusmj38型 | 1300591 |
错误C2131:表达式的计算结果不是常量 | camhusmj38型 | 1596224 |
MSVC 2015认为constexpr成员指针不是常量 | 大卫·马涅默 | 1327934 |
MSVC 2015在constexpr上下文中的指针算法崩溃 | 大卫·马涅默 | 1420558 |
MSVC 2015尝试评估constexpr构造函数时崩溃 初始化一个引用 | 大卫·马涅默 | 1404631 |
MSVC 2015尝试计算包含指向成员函数的指针的constexpr时崩溃 | 大卫·马涅默 | 1327996 |
MSVC 2015错误地拒绝联合访问的constexpr数组 | 大卫·马涅默 | 1323869 |
MSVC 2015错误地拒绝constexpr上下文中的指针相等 | 大卫·马涅默 | 1404624 |
MSVC 2015在constexpr上下文中实现了一个常量而不是两个常量 | 大卫·马涅默 | 1404688 |
MSVC 2015拒绝初始化对临时对象的constexpr引用 | 大卫·马涅默 | 1404715 |
MSVC 2015拒绝constexpr上下文中const int类型的左值条件运算符 | 大卫·马涅默 | 1404674 |
MSVC 2015拒绝constexpr上下文中的成员指针比较 | 大卫·马涅默 | 1401241 |
MSVC2015拒绝valid并接受无效的constexpr static u cast | 大卫·马涅默 | 1330530 |
MSVC 2015不会对函数本地静态constexpr引用变量求值 暂时的 | 大卫·马涅默 | 1404755 |
未能使用“constexpr”的有效用法进行编译 | dn357型 | 1311469 |
std::makeu数组建议实现的constexpr语句中出现编译器故障 | 菲利克斯·彼得里科尼 | 1494444 |
`std::integral_constant<>`隐式定义的默认构造函数和/或`operator value_type`not 常量表达式 | 伊尔贾恩 | 1497236 |
试图在constexpr函数内部进行聚合初始化时,返回临时函数的地址或引用的错误 | 伊尔贾恩 | 1498733 |
C++-COSTEXPR不适用于聚合初始化 | 伊尔贾恩 | 1572056 |
C++-COSTEXPR不与委派构造函数一起工作 | 伊尔贾恩 | 1579279 |
C++定义的静态成员函数在类型定义中被调用时必须完全限定 | 伊尔贾恩 | 1579334 |
C++——用CONTXPR构造函数编写内部编译器错误 | 伊尔贾恩 | 1571950 |
[constexpr]函数指针constexpr推导错误 | 库什 | 1378031 |
在constexpr lambda解决方案中失败 | mzer0型 | 1673865 |
VC++2015 RTM–带位字段的联合成员的constexpr构造函数错误 | 奥维德国王 | 1571281 |
constexpr和循环模板导致致命错误C1001 | 彭德纳 | 1711144 |
类静态constexpr值为0 | pmingkr公司 | 1384724 |
constexpr委托构造函数不编译 | 吉诃德实验室 | 1229998 |
与“char const*const”参数相关的constexpr错误 | Rui Figueira(云引擎) | 1272743 |
非类型模板实例化的[constexpr][regression][boost]VC++内部编译器错误 | 萨沙·西特尼科夫 | 1577162 |
在constexpr ctor中委托构造函数将无法编译 | 提交错误报告太难了 | 1463556 |
编译此C/C++代码时的ICE | ||
由变量递归constexpr触发的伪错误C2131“表达式未计算为常量” | ||
constexpr委托构造函数 | ||
当从结构模板内调用constexpr template函数时,会导致编译失败,并显示错误消息 | ||
constexpr 4607“ptr”触发结冰?在constexpr函数中为3:4“ |
期待
即便是对用更新1进行传输的C++ 11 CONTHEXPR的改进,我们在实现上仍有一些改进。在这个领域,我们的backlog中还有大约30个bug,其中许多与指向常量表达式中成员的指针有关。围绕数组和字符串别名还有一些高质量的工作要做,尽管Tanveer在准备静态初始值设定项方面做得很好,但我们正在计划一些与更改相关的错误报告。
基本上,所有这些都意味着我们将继续工作C++ 11 CysExPR更长的时间,但出色的工作是可管理的。我们的目标是在visualstudio的下一次更新中及时完成这项工作。之后的计划是立即跳入C++ 14的CONTXPR支持。
科迪米勒
Visual C++团队