{"id":107393,"date":"2022-11-14T07:00:00","date_gmt":"2022-11-14T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107393"},"modified":"2022-11-14T06:37:52","modified_gmt":"2022-11-14T14:37:52","slug":"20221114-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221114-00\/?p=107393","title":{"rendered":"C++ constexpr parlor tricks: How can I obtain the length of a string at compile time?"},"content":{"rendered":"<p>Say you want to obtain, at compile time, the length of a compile-time string constant. The problem is that the <code>strlen<\/code> function is not <code>constexpr<\/code>.<\/p>\n<pre>#include &lt;cstring&gt;\r\n\r\ntemplate&lt;std::size_t&gt; void tryme();\r\n\r\nvoid test()\r\n{\r\n    \/\/ error; expression did not evaluate to a constant\r\n    char buffer[strlen(\"hello\") + 1];\r\n\r\n    \/\/ error: invalid template argument\r\n    tryme&lt;strlen(\"hello\")&gt;();\r\n\r\n    switch (0)\r\n    {\r\n    \/\/ error: case expression is not constant\r\n    case strlen(\"hello\"): break;\r\n    }\r\n}\r\n<\/pre>\n<p>Note that gcc and clang support variable-length arrays as a nonstandard extension, so you may get away with the <code>buffer<\/code> declaration unless you turn off that extension. In fact, gcc goes further and accepts all three statements!<\/p>\n<p>How can you get all three of the above to work in standard-conforming code? One idea is to write your own <code>constexpr_strlen<\/code>. But it turns out that somebody already wrote it for you, although it has a rather awkward name: <code>std::<wbr \/>char_traits&lt;T&gt;::<wbr \/>length()<\/code>.<\/p>\n<pre>#include &lt;string&gt;\r\n\r\nconstexpr std::size_t constexpr_strlen(const char* s)\r\n{\r\n    return std::char_traits&lt;char&gt;::length(s);\r\n    \/\/ or\r\n    return std::string::traits_type::length(s);\r\n}\r\n\r\nconstexpr std::size_t constexpr_wcslen(const wchar_t* s)\r\n{\r\n    return std::char_traits&lt;wchar_t&gt;::length(s);\r\n    \/\/ or\r\n    return std::wstring::traits_type::length(s);\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>The <CODE>constexpr<\/CODE>&#8216;ification of <CODE>strlen<\/CODE>.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-107393","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The <CODE>constexpr<\/CODE>&#8216;ification of <CODE>strlen<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107393","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107393"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107393\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107393"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107393"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107393"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}