{"id":10150,"date":"2024-10-14T09:42:42","date_gmt":"2024-10-14T09:42:42","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=10150"},"modified":"2025-07-04T14:04:07","modified_gmt":"2025-07-04T14:04:07","slug":"reflection-in-c26-determine-the-layout","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/reflection-in-c26-determine-the-layout\/","title":{"rendered":"Reflection in C++26: Determine the Layout"},"content":{"rendered":"\n<p>Thanks to reflection, you can determine the layout of types.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"696\" height=\"537\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/09\/Time26Reflection.png\" alt=\"\" class=\"wp-image-10083\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/09\/Time26Reflection.png 696w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/09\/Time26Reflection-300x231.png 300w\" sizes=\"auto, (max-width: 696px) 100vw, 696px\" \/><\/figure>\n\n\n\n<p>My examples are based on the reflection proposal <a href=\"https:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2024\/p2996r5.html\">P2996R5<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Class Layout<\/h2>\n\n\n\n<p>The following program determines the class layout of a few members.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ classLayout.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;experimental\/meta&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;utility&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;vector&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;array&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold\">struct<\/span> member_descriptor\n{\n  std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">size_t<\/span> offset;\n  std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">size_t<\/span> size;\n  <span style=\"color: #007788; font-weight: bold\">bool<\/span> <span style=\"color: #006699; font-weight: bold\">operator<\/span><span style=\"color: #555555\">==<\/span>(member_descriptor <span style=\"color: #006699; font-weight: bold\">const<\/span><span style=\"color: #555555\">&amp;<\/span>) <span style=\"color: #006699; font-weight: bold\">const<\/span> <span style=\"color: #555555\">=<\/span> <span style=\"color: #006699; font-weight: bold\">default<\/span>;\n};\n\n<span style=\"color: #0099FF; font-style: italic\">\/\/ returns std::array&lt;member_descriptor, N&gt; The company&#39;s biggest funding.<\/span>\n<span style=\"color: #006699; font-weight: bold\">template<\/span> <span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">typename<\/span> S<span style=\"color: #555555\">&gt;<\/span>\nconsteval <span style=\"color: #006699; font-weight: bold\">auto<\/span> get_layout() {\n  constexpr <span style=\"color: #007788; font-weight: bold\">size_t<\/span> N <span style=\"color: #555555\">=<\/span> []() consteval {\n    <span style=\"color: #006699; font-weight: bold\">return<\/span> nonstatic_data_members_of(<span style=\"color: #555555\">^<\/span>S).size();\n  }();\n\n  std<span style=\"color: #555555\">::<\/span>array<span style=\"color: #555555\">&lt;<\/span>member_descriptor, N<span style=\"color: #555555\">&gt;<\/span> layout;\n  [<span style=\"color: #555555\">:<\/span> expand(nonstatic_data_members_of(<span style=\"color: #555555\">^<\/span>S)) <span style=\"color: #555555\">:<\/span>] <span style=\"color: #555555\">&gt;&gt;<\/span> [<span style=\"color: #555555\">&amp;<\/span>, i<span style=\"color: #555555\">=<\/span><span style=\"color: #FF6600\">0<\/span>]<span style=\"color: #555555\">&lt;<\/span><span style=\"color: #006699; font-weight: bold\">auto<\/span> e<span style=\"color: #555555\">&gt;<\/span>() <span style=\"color: #006699; font-weight: bold\">mutable<\/span> {\n    layout[i] <span style=\"color: #555555\">=<\/span> {.offset<span style=\"color: #555555\">=<\/span>offset_of(e), .size<span style=\"color: #555555\">=<\/span>size_of(e)};\n    <span style=\"color: #555555\">++<\/span>i;\n  };\n  <span style=\"color: #006699; font-weight: bold\">return<\/span> layout;\n}\n\n<span style=\"color: #006699; font-weight: bold\">struct<\/span> X\n{\n    <span style=\"color: #007788; font-weight: bold\">char<\/span> a;\n    <span style=\"color: #007788; font-weight: bold\">int<\/span> b;\n    <span style=\"color: #007788; font-weight: bold\">double<\/span> c;\n};\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    \n    constexpr <span style=\"color: #006699; font-weight: bold\">auto<\/span> layout <span style=\"color: #555555\">=<\/span> get_layout<span style=\"color: #555555\">&lt;<\/span>X<span style=\"color: #555555\">&gt;<\/span>();\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Layout of struct X:<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    <span style=\"color: #006699; font-weight: bold\">for<\/span> (<span style=\"color: #006699; font-weight: bold\">const<\/span> <span style=\"color: #006699; font-weight: bold\">auto<\/span><span style=\"color: #555555\">&amp;<\/span> member <span style=\"color: #555555\">:<\/span> layout) {\n        std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Offset: &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> member.offset <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;, Size: &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> member.size <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    }\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n\n}\n<\/pre><\/div>\n\n\n\n<p>The C++ program reflects on the layout of a struct&#8217;s data members. The main goal of this code is to determine and print the memory offsets and sizes of each member within a struct.<\/p>\n\n\n\n<p>The first part of the code defines a <code>std::array<\/code> named <code>layout<\/code>, which is intended to store descriptors for each member of the struct. These descriptors include the offset and size of each member. The <code>[: expand(nonstatic_data_members_of(^S)) :]<\/code> construct is a placeholder for a metaprogramming construct that iterates over the non-static data members of the struct <code>S<\/code>. This construct is only a temporary workaround and is followed by a lambda function that captures the current state by reference (<code>&amp;<\/code>) and initializes an index variable <code>i<\/code> to zero. The lambda function is then applied to each data member, storing the offset and size of each member in the <code>layout<\/code> array and incrementing the index <code>i<\/code>.<\/p>\n\n\n\n<p>The <code>struct X<\/code> is defined with three data members: a <code>char<\/code> named <code>a<\/code>, an <code>int<\/code> named <code>b<\/code>, and a <code>double<\/code> named <code>c<\/code>. These members are used to demonstrate the reflection mechanism.<\/p>\n\n\n\n<p>In the <code>main<\/code> calls a function <code>get_layout&lt;X&gt;()<\/code>, which returns the <code>layout<\/code> array filled with the offsets and sizes of the members of <code>struct X<\/code>. The program then prints the layout of <code>struct <\/code><a href=\"command:_github.copilot.openSymbolFromReferences?%5B%22%22%2C%5B%7B%22uri%22%3A%7B%22scheme%22%3A%22file%22%2C%22authority%22%3A%22%22%2C%22path%22%3A%22%2FC%3A%2FUsers%2Fseminar%2FDropbox%2Fblog%2Fressourcen%2FC%2B%2B26%2FReflectionClassLayout%2FreflectionClassLayout.cpp%22%2C%22query%22%3A%22%22%2C%22fragment%22%3A%22%22%7D%2C%22pos%22%3A%7B%22line%22%3A30%2C%22character%22%3A7%7D%7D%5D%2C%2218f522d2-9b93-4f04-b35f-6a9bf898be9b%22%5D\"><code>X<\/code><\/a> by iterating over the <code>layout<\/code> array and printing the offset and size of each member.<\/p>\n\n\n\n<p>This code reflects on the memory layout of a struct&#8217;s data members in C++, which can be useful for understanding memory alignment and optimizing data structures.<\/p>\n\n\n\n<p>Finally, he has the output of the program:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"237\" height=\"124\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/10\/reflectionClassLayout.png\" alt=\"\" class=\"wp-image-10154\"\/><\/figure>\n\n\n\n<p>You can store reflections in a container or apply an algorithm to them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Size<\/h2>\n\n\n\n<p>The following program determines the size of a few built-in types.<\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\"><span style=\"color: #0099FF; font-style: italic\">\/\/ getSize.cpp<\/span>\n\n<span style=\"color: #009999\">#include &lt;experimental\/meta&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;array&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;ranges&gt;<\/span>\n<span style=\"color: #009999\">#include &lt;algorithm&gt; <\/span>\n\nconstexpr std<span style=\"color: #555555\">::<\/span>array types <span style=\"color: #555555\">=<\/span> {<span style=\"color: #555555\">^<\/span><span style=\"color: #007788; font-weight: bold\">int<\/span>, <span style=\"color: #555555\">^<\/span><span style=\"color: #007788; font-weight: bold\">float<\/span>, <span style=\"color: #555555\">^<\/span><span style=\"color: #007788; font-weight: bold\">double<\/span>};\nconstexpr std<span style=\"color: #555555\">::<\/span>array sizes <span style=\"color: #555555\">=<\/span> []{\n  std<span style=\"color: #555555\">::<\/span>array<span style=\"color: #555555\">&lt;<\/span>std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">size_t<\/span>, types.size()<span style=\"color: #555555\">&gt;<\/span> r;\n  std<span style=\"color: #555555\">::<\/span>ranges<span style=\"color: #555555\">::<\/span>transform(types, r.begin(), std<span style=\"color: #555555\">::<\/span>meta<span style=\"color: #555555\">::<\/span>size_of);\n  <span style=\"color: #006699; font-weight: bold\">return<\/span> r;\n}();\n\n<span style=\"color: #007788; font-weight: bold\">int<\/span> <span style=\"color: #CC00FF\">main<\/span>() {\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    \n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Types and their sizes:<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    <span style=\"color: #006699; font-weight: bold\">for<\/span> (std<span style=\"color: #555555\">::<\/span><span style=\"color: #007788; font-weight: bold\">size_t<\/span> i <span style=\"color: #555555\">=<\/span> <span style=\"color: #FF6600\">0<\/span>; i <span style=\"color: #555555\">&lt;<\/span> types.size(); <span style=\"color: #555555\">++<\/span>i) {\n        std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot;Size: &quot;<\/span> <span style=\"color: #555555\">&lt;&lt;<\/span> sizes[i] <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&quot; bytes<\/span><span style=\"color: #CC3300; font-weight: bold\">\\n<\/span><span style=\"color: #CC3300\">&quot;<\/span>;\n    }\n\n    std<span style=\"color: #555555\">::<\/span>cout <span style=\"color: #555555\">&lt;&lt;<\/span> <span style=\"color: #CC3300\">&#39;\\n&#39;<\/span>;\n    \n}\n<\/pre><\/div>\n\n\n\n<p>The program begins by including several headers: <code>&lt;experimental\/meta&gt;<\/code> for reflection capabilities, <code>&lt;array&gt;<\/code> for fixed-size array support, <code>&lt;iostream&gt;<\/code> for input\/output operations, <code>&lt;ranges&gt;<\/code> for range-based algorithms, and <code>&lt;algorithm&gt;<\/code> for general algorithms.<\/p>\n\n\n\n<p>The <code>constexpr std::array types<\/code> declaration creates a compile-time array containing reflections for <code>int<\/code>, <code>float<\/code>, and <code>double<\/code>. These reflections are represented using the reflection operator <code>^<\/code>.<\/p>\n\n\n\n<p>Next, the <code>constexpr std::array sizes<\/code> declaration defines another compile-time array that will hold the sizes of the types specified in the <code>types<\/code> array. This array is initialized using a lambda function that creates an array <code>r<\/code> of the same size as <code>types<\/code>. The <code>std::ranges::transform<\/code> function is then used to populate <code>r<\/code> by applying the <code>std::meta::size_of<\/code> operation to each reflection value in <code>types<\/code>. The <code>std::meta::size_of<\/code> operation is a metafunction that returns the size of a type at compile time.<\/p>\n\n\n\n<p>The <code>main<\/code> function begins by entering a loop that iterates over the indices of the <code>types<\/code> array. For each index, it prints the size of the corresponding type from the <code>sizes<\/code> array in bytes.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"268\" height=\"146\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2024\/10\/getSize.png\" alt=\"\" class=\"wp-image-10219\" style=\"width:300px\"\/><\/figure>\n\n\n\n<p>Instead of the ranges function <code>std::ranges::transform<\/code>,  you could also use the classical transform algorithm; <\/p>\n\n\n\n<!-- HTML generated using hilite.me --><div style=\"background: #f0f3f3; overflow:auto;width:auto;gray;border-width:.1em .1em .1em .8em\"><pre style=\"margin: 0; line-height: 125%\">std<span style=\"color: #555555\">::<\/span>transform(types.begin(), types.end(), r.begin(), std<span style=\"color: #555555\">::<\/span>meta<span style=\"color: #555555\">::<\/span>size_of);\n<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"> What&#8217;s Next? <\/h2>\n\n\n\n<p>This was my first dive into reflection in C++26. A deeper dive will follow. In my next post, I will focus on contracts. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Thanks to reflection, you can determine the layout of types. My examples are based on the reflection proposal P2996R5. Class Layout The following program determines the class layout of a few members. \/\/ classLayout.cpp #include &lt;experimental\/meta&gt; #include &lt;iostream&gt; #include &lt;utility&gt; #include &lt;vector&gt; #include &lt;array&gt; struct member_descriptor { std::size_t offset; std::size_t size; bool operator==(member_descriptor const&amp;) const [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":10083,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[559],"tags":[560],"class_list":["post-10150","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c26-blog","tag-reflection"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10150","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=10150"}],"version-history":[{"count":13,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10150\/revisions"}],"predecessor-version":[{"id":10221,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/10150\/revisions\/10221"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/10083"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=10150"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=10150"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=10150"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}