{"id":12835,"date":"2017-03-07T10:01:11","date_gmt":"2017-03-07T17:01:11","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vcblog\/?p=12835"},"modified":"2019-02-18T17:48:41","modified_gmt":"2019-02-18T17:48:41","slug":"constexpr-and-aggregate-initialization","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/constexpr-and-aggregate-initialization\/","title":{"rendered":"C++14 conformance improvements: constexpr and aggregate initialization"},"content":{"rendered":"<p>Two important features in C++11 received small upgrades in C++14 that had far-reaching effects.<\/p>\n<ol>\n<li>In C++11, <code>constexpr<\/code> function bodies were allowed only to be a single <code>return<\/code> statement. In C++14, nearly all statements are now allowed in <code>constexpr<\/code> functions, allowing for much more idiomatic C++. You can learn more about what\u2019s allowed in <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/constant_expression#Core_constant_expression\">core constant expressions on CppReference<\/a> as well as <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/constexpr\">learn about <code>constexpr<\/code> on the same site<\/a>.<\/li>\n<li>An aggregate type in C++11 could not be initialized as an aggregate if it contained any members that had default member initializers. In C++14 the committee removed this restriction on non-static data members having default member initializers. You can find out more about <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/aggregate_initialization\">aggregate initialization on CppReference<\/a> as well as about <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/language\/data_members#Member_initialization\">non-static data member initialization<\/a> (known as NSDMI.)<\/li>\n<\/ol>\n<p>You can see from the <a href=\"http:\/\/en.cppreference.com\">CppReference site<\/a> that while both of these changes were small changes to the standard (search for the &#8220;C++14&#8221; annotation on those pages) they had broad impact on the compiler\u2019s implementation and on what code developers can write.<\/p>\n<ul>\n<li>Previously, <code>constexpr<\/code> was basically all about expressions, but C++14 extended it to allow control flow statements. The difference in what you can write in your code is huge: now instead of just being able to write expressions you can create idiomatic compile-time value compilations and mutation.<\/li>\n<li>The changes to allow aggregate initialization for aggregates that contain non-static data members makes a useful case of aggregate initialization possible.<\/li>\n<\/ul>\n<p>We\u2019re happy to announce that the compiler shipping with Visual Studio 2017 supports both extended constexpr and NSDMI for aggregates fully.<\/p>\n<h4>Extended constexpr<\/h4>\n<p>Our extended constexpr work was test-driven. We tested against a number of libraries that are heavy users of extended <code>constexpr<\/code>, including:<\/p>\n<ul>\n<li>Sprout<\/li>\n<li>Boost (with MSVC workarounds removed)<\/li>\n<li>Boost Hana<\/li>\n<li>Guidelines Support Library (GSL)<\/li>\n<li>libc++ tests<\/li>\n<li>Microsoft&#8217;s Range-v3 fork<\/li>\n<li>C++ Standard Libraries<\/li>\n<\/ul>\n<p>We&#8217;ve also evaluated against test suites from McCluskey, Plumhall, and Perennial, as well as a test suite built from code snippets you sent us from an online survey, online forums, and early bug reports from the VC Blog.<\/p>\n<p>Taking advantage of C++14 <code>constexpr<\/code> is almost as easy as putting the <code>constexpr<\/code> keyword on existing functions, because extended <code>constexpr<\/code> allows a developer to use idiomatic C++ for their <code>constexpr<\/code> functions.<\/p>\n<ul>\n<li>Local variable declarations and conditionals can now be used in <code>constexpr<\/code> functions. [see example 1 below]<\/li>\n<li>Instead of recursion, all looping constructs (except goto) are allowed in constexpr functions [see example 2 below]<\/li>\n<\/ul>\n<p>Using iteration instead of recursion should perform better at compile time, and, as <code>constexpr<\/code> functions can be used at runtime, will perform better at runtime as well. We&#8217;ve beefed up our <code>constexpr<\/code> control flow engine to eagerly identify cases where a <code>constexpr<\/code> function is guaranteed to evaluate illegal expressions, so a class of errors can be caught at <code>constexpr<\/code>-authoring time rather than after a library has been shipped to developers.<\/p>\n<h4>constexpr examples<\/h4>\n<pre class=\"prettyprint\">\n\/\/ Example 1a\nenum class Messages { \n\tHi, \n\tGoodbye \n};\n\nconstexpr Messages switch_with_declaration_in_control(int x)\n{\n    switch (int value = x)\n    {\n        case 0:                 return Messages::Hi;\n        default: return Messages::Goodbye;\n    }\n}\n\n\n\/\/ Example 1b\nconstexpr bool even(int x) {\n\tif (x % 2 == 0)\n\t\treturn true;\n\treturn false;\n}\n\n\/\/ Example 2a\nconstexpr int simple_count_up_do_loop(int x) {\n\tint i = 0;\n\tdo\t{\n\t\t++i;\n\t} while (i &lt; x);\n\treturn i;\n}\n\n\/\/ Example 2b\nconstexpr int multiple_initializers_multiple_incr_count_up(int x) {\n\tint higher = 0;\n\tfor (auto i = 0, j = 1; i &lt;= x; ++i, j++)\n\t\thigher = j;\n\treturn higher;\n}\n\n\/\/ Negative test cases\nconstexpr bool always(int x) {\n\treturn x;\n}\n\nconstexpr int guaranteed_to_hit_true_path() {\n\tif (always(1))\n\t\tthrow &quot;OH NO&quot;; \/\/ illegal expression, guaranteed to be hit\n\treturn 0;\n}\n\nconstexpr int guaranteed_to_hit_false_path() {\n\tif (42 * 2 - 84)\n\t\treturn 1;\n\telse\n\t\tthrow &quot;OH NO&quot;; \/\/ illegal expression, guaranteed to be hit\n\treturn 0;\n}\n\nconstexpr int guaranteed_to_evaluate_while_loop() {\n\twhile (always(33)) {\n\t\tnew int(0);    \/\/ illegal expression, guaranteed to be hit\n\t}\n\treturn 0;\n}\n\nconstexpr int guaranteed_to_evaluate_for_loop() {\n\tfor (; always(22); )\n\t\tnew int();     \/\/ illegal expression, guaranteed to be hit\n\treturn 0;\n}\n<\/pre>\n<h4>NSDMI for aggregates<\/h4>\n<p>The NSDMI for aggregates changes were more limited in scope but automatically improve a lot of existing code. In C++ 11, the presence of a default member initializer (NSDMI) would preclude the class from being an aggregate; therefore, it would not be eligible for aggregate initialization.<\/p>\n<p>An example:<\/p>\n<pre class=\"prettyprint\"> \nstruct S {\n  int i = 1;\n  int j = 2;\n};\n \nS s1;   \/\/ OK; calls the default constructor, which initializes 'i' and 'j' to 1 and 2.\nS s2{}; \/\/ OK; not aggregate initialization because S is not an aggregate; calls the default constructor.\ns3{42}; \/\/ Error; S is not an aggregate and there is no appropriate constructor.\n<\/pre>\n<p>In C++14, S is now considered to be an aggregate class type, so aggregate initialization can be used:<\/p>\n<pre class=\"prettyprint\"> \nS 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.\nS 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.\n<\/pre>\n<h4>In closing<\/h4>\n<p>As always, we welcome your feedback. Feel free to send any comments through e-mail at <a>visualcpp@microsoft.com<\/a>, through <a href=\"https:\/\/twitter.com\/visualc\">Twitter @visualc<\/a>, or Facebook at <a href=\"https:\/\/www.facebook.com\/Microsoft-Visual-Cpp-222043184527264\/\">Microsoft Visual Cpp<\/a>.<\/p>\n<p>If you encounter other problems with Visual C++ in VS 2017 please let us know via the Report a Problem option, either from the installer or the Visual Studio IDE itself. For suggestions, let us know through <a href=\"https:\/\/visualstudio.uservoice.com\/forums\/121579-visual-studio-2015\/category\/30937-languages-c\">UserVoice<\/a>. Thank you!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Two important features in C++11 received small upgrades in C++14 that had far-reaching effects. In C++11, constexpr function bodies were allowed only to be a single return statement. In C++14, nearly all statements are now allowed in constexpr functions, allowing for much more idiomatic C++. You can learn more about what\u2019s allowed in core constant [&hellip;]<\/p>\n","protected":false},"author":312,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[270],"tags":[],"class_list":["post-12835","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcement"],"acf":[],"blog_post_summary":"<p>Two important features in C++11 received small upgrades in C++14 that had far-reaching effects. In C++11, constexpr function bodies were allowed only to be a single return statement. In C++14, nearly all statements are now allowed in constexpr functions, allowing for much more idiomatic C++. You can learn more about what\u2019s allowed in core constant [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/12835","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/312"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=12835"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/12835\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=12835"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=12835"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=12835"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}