C++ 11中的两个重要特性在C++ 14中有了微小的升级,具有深远的影响。
- 在C++ 11中,
constexpr
职能机构只能是一个单独的机构return
声明。在C++ 14中,几乎所有语句都被允许输入constexpr
函数,允许更多的习惯性C++。你可以了解更多关于什么是允许的 cppference上的核心常量表达式 以及 了解constexpr
在同一地点 . - 如果包含任何默认成员初始化器的成员,C++ 11中的聚合类型不能作为聚合初始化。在C++ 14中,委员会取消了对具有默认成员初始化器的非静态数据成员的限制。你可以找到更多关于 CppReference上的聚合初始化 以及关于 非静态数据成员初始化 (称为NSDMI)
你可以从照片上看到 CPP参考站点 虽然这两个更改都是对标准的小更改(在这些页面上搜索“C++14”注释),但它们对编译器的实现和代码开发人员可以编写的代码有着广泛的影响。
- 以前,
constexpr
基本上都是关于表达式,但是C++ 14扩展了它来允许控制流语句。您可以在代码中编写的内容之间的差别是巨大的:现在您可以创建惯用的编译时值编译和变异,而不仅仅是编写表达式。 - 允许对包含非静态数据成员的聚合进行聚合初始化的更改使聚合初始化成为可能。
我们很高兴地宣布,Visual Studio 2017附带的编译器完全支持extended constexpr和NSDMI for aggregates。
扩展constexpr
我们的扩展constexpr工作是测试驱动的。我们针对大量使用扩展服务的库进行了测试 constexpr
,包括:
- 发芽
- Boost(去掉MSVC解决方法)
- 增强Hana
- 指南支持库(GSL)
- libc++测试
- 微软的Range-v3 fork
- C++标准库
我们还评估了来自McCluskey、Plumhall和Periornian的测试套件,以及您从在线调查、在线论坛和VC博客的早期bug报告中发送给我们的代码片段构建的测试套件。
利用C++ 14 constexpr
几乎和把 constexpr
现有函数上的关键字,因为已扩展 constexpr
允许开发人员使用惯用的C++来实现它们的 constexpr
功能。
- 局部变量声明和条件现在可以在
constexpr
功能[参见下面的示例1] - 在constexpr函数中允许所有循环构造(goto除外),而不是递归[参见下面的示例2]
使用迭代而不是递归应该在编译时执行得更好,而且 constexpr
函数可以在运行时使用,也可以在运行时执行得更好。我们已经加强了我们的工作 constexpr
控制流引擎以急切地识别 constexpr
函数保证对非法表达式进行求值,因此可以同时捕获一类错误 constexpr
-创作时间,而不是库交付给开发人员之后。
constexpr示例
// Example 1aenum class Messages { Hi, Goodbye };constexpr Messages switch_with_declaration_in_control(int x){ switch (int value = x) { case 0: return Messages::Hi; default: return Messages::Goodbye; }}// Example 1bconstexpr bool even(int x) { if (x % 2 == 0) return true; return false;}// Example 2aconstexpr int simple_count_up_do_loop(int x) { int i = 0; do { ++i; } while (i < x); return i;}// Example 2bconstexpr int multiple_initializers_multiple_incr_count_up(int x) { int higher = 0; for (auto i = 0, j = 1; i <= x; ++i, j++) higher = j; return higher;}// Negative test casesconstexpr bool always(int x) { return x;}constexpr int guaranteed_to_hit_true_path() { if (always(1)) throw "OH NO"; // illegal expression, guaranteed to be hit return 0;}constexpr int guaranteed_to_hit_false_path() { if (42 * 2 - 84) return 1; else throw "OH NO"; // illegal expression, guaranteed to be hit return 0;}constexpr int guaranteed_to_evaluate_while_loop() { while (always(33)) { new int(0); // illegal expression, guaranteed to be hit } return 0;}constexpr int guaranteed_to_evaluate_for_loop() { for (; always(22); ) new int(); // illegal expression, guaranteed to be hit return 0;}
骨料NSDMI
NSDMI for aggregates的更改范围更有限,但会自动改进许多现有代码。在C++ 11中,默认成员初始化器(NSDMI)的存在会阻止类成为聚合;因此,它没有资格进行聚合初始化。
举个例子:
struct S { int i = 1; int j = 2;}; S s1; // OK; calls the default constructor, which initializes 'i' and 'j' to 1 and 2.S s2{}; // OK; not aggregate initialization because S is not an aggregate; calls the default constructor.s3{42}; // Error; S is not an aggregate and there is no appropriate constructor.
在C++ 14中,S被认为是一个聚合类类型,因此可以使用聚合初始化:
S s4{}; // OK with C++14; aggregate initialization; no initializer is provided for 'i' or 'j', so their respective default member initializers will be used to initialize them to 1 and 2.S s5{42}; // OK with C++14; aggregate initialization; 'i' is explicitly initialized to 42 and no initializer is provided for 'j', so its default member initializer will be used to initialize it to 2.
最后
一如既往,我们欢迎您的反馈。欢迎通过电子邮件发送任何评论 visualcpp@microsoft.com ,通过 推特@visualc ,或Facebook Microsoft Visual Cpp .
如果您在VS 2017中遇到VisualC++的其他问题,请通过报告从安装程序或VisualStudioIDE本身通知我们一个问题选项。如需建议,请告知我们 用户语音 . 谢谢您!