November 14th, 2022

C++ constexpr parlor tricks: How can I obtain the length of a string at compile time?

Say you want to obtain, at compile time, the length of a compile-time string constant. The problem is that the strlen function is not constexpr.

#include <cstring>

template<std::size_t> void tryme();

void test()
{
    // error; expression did not evaluate to a constant
    char buffer[strlen("hello") + 1];

    // error: invalid template argument
    tryme<strlen("hello")>();

    switch (0)
    {
    // error: case expression is not constant
    case strlen("hello"): break;
    }
}

Note that gcc and clang support variable-length arrays as a nonstandard extension, so you may get away with the buffer declaration unless you turn off that extension. In fact, gcc goes further and accepts all three statements!

How can you get all three of the above to work in standard-conforming code? One idea is to write your own constexpr_strlen. But it turns out that somebody already wrote it for you, although it has a rather awkward name: std::char_traits<T>::length().

#include <string>

constexpr std::size_t constexpr_strlen(const char* s)
{
    return std::char_traits<char>::length(s);
    // or
    return std::string::traits_type::length(s);
}

constexpr std::size_t constexpr_wcslen(const wchar_t* s)
{
    return std::char_traits<wchar_t>::length(s);
    // or
    return std::wstring::traits_type::length(s);
}
Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

7 comments

Discussion is closed. Login to edit/delete existing comments.

  • 大狗皇帝

    in winnt.h:

    //
    // Return the number of elements in a statically sized array.
    // DWORD Buffer[100];
    // RTL_NUMBER_OF(Buffer) == 100
    // This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
    //
    #define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))

  • Dennis Mabrey

    I still would probably use sizeof(“wazzup”)-1 just because it is more readable.

    As a side note one of my C/C++ gotcha questions to students is to ask what is the value of i.

    int i=42;
    int j = sizeof(i++);
    
    • Raymond ChenMicrosoft employee Author

      But sizeof("wazzup") requires an embedded literal.

      constexpr int tmplen(char const* prefix)
      {
          return std::char_traits::length(prefix) + 5;
      }
      
      void mktemp(char* buffer, char const* prefix)
      {
          strcpy(buffer, prefix);
          strcat(buffer, "temp");
      }
      
      void test()
      {
          constexpr char const* prefix = "hello";
          char buffer[tmplen(prefix)];
          mktemp(buffer, prefix);
      }
      

      The corresponding sizeof(s) - 1 produces the wrong answer.

  • some thing

    constexpr auto a = std::string_view(“hello”).size();

  • Nikl Kelbon

    Please next article “don’t use clang and gcc extensions with variable arrays along with coroutines”, i dont rly know why it is not ill-formed in clang

  • Martin “KeyJ” Fiedler

    The problem with std::char_traits::length() is that it’s only constexpr since C++17 (at least according to https://en.cppreference.com/w/cpp/string/char_traits/length).
    If C++11-to-14 compatibility is desired, there’s no way around something like

    constexpr std::size_t constexpr_strlen(const char* s) {
        return (s && s[0]) ? (constexpr_strlen(&s[1]) + 1) : 0;
    }
  • Joshua Hudson · Edited

    > In fact, gcc goes further and accepts all three statements!

    As far as I can tell, gcc is smart enough to treat strlen as constexpr until told otherwise. (By telling it strlen is not an intrinsic.) This property also allows gcc to hoist strlen() invocations out of loop tests most of the time.

    Older way of getting the length of a string at compile time: (sizeof("hello") - 1)

    Wait isn't the first one just C99 variable length...

    Read more