Skip to content

Latest commit

 

History

History
115 lines (89 loc) · 3.94 KB

File metadata and controls

115 lines (89 loc) · 3.94 KB

ct_string.hpp

A ct_string is a compile-time string that can be used as a non-type template parameter (NTTP).

Note
ct_string is available only in C++20 and later. It requires compiler support for using structural types as NTTPs.

Example usage:

template <ct_string S>
struct named_thing { ... };

auto my_thing = named_thing<"mine">{};

Here we declare a struct with an NTTP, and instantiate the template with a string. When compiled, "mine" will create a ct_string which is the NTTP passed to named_thing.

Note
ct_string is a class template. The declaration of named_thing here uses ct_string as a placeholder type for an NTTP, whose concrete type will be deduced. This is new for C++20 - see https://en.cppreference.com/w/cpp/language/template_parameters for details.

The ct_string interface:

template <ct_string S>
struct named_thing {
  template <ct_string Other>
  auto f() {
    // here we can:
    constexpr std::size_t sz = S.size();  // ask for ct_string's size
    constexpr bool is_empty = S.empty();  // ask whether a ct_string is empty
    constexpr bool equal = S == Other;    // compare two ct_strings

    // we can also convert to/from cib string constants
    constexpr auto cib_sc_string = stdx::ct_string_to_type<S, sc::string_constant>();
    constexpr auto stdx_ct_string = stdx::ct_string_from_type(cib_sc_string);
    static_assert(S == stdx_ct_string);

    // we can make a ct_string with a UDL:
    using namespace stdx::ct_string_literals;
    constexpr auto s = "Hello"_cts;

    // we can concatenate two ct_strings:
    constexpr auto s1 = "abc"_cts;
    constexpr auto s2 = "def"_cts;
    constexpr auto s3 = s1 + s2; // abcdef

    // and we can split a ct_string at the first occurrence of a character,
    // optaining a pair of ct_strings
    constexpr auto p = stdx::split<S, '/'>();
    // if the character doesn't exist, p.first is equal to S and p.second is empty
    // otherwise p.first is everything up to (but not including) the character,
    // and p.second is everything after (also not including)

    // we can also iterate over a ct_string
    for (auto c : S) { ... }

    // a ct_string can also explicitly convert to a std::string_view
    constexpr auto sv = static_cast<std::string_view>(S);

    // when required, we can access the underlying array of chars,
    // which includes the null terminator
    const auto& char_array = S.value;
  }
};
Note
size and empty are always available as constexpr.
Note
_cts is a user-defined literal declared in stdx::literals::ct_string_literals, where both literals and ct_string_literals are inline namespaces.
Caution
ct_string stores an internal array (value) which includes the null terminator for the string. The size reported by the ct_string is one less than the size of the internal array. Thus the begin, end and size of a ct_string all represent the string of characters without the null terminator. However, for interfacing with legacy functions, a null terminator can be useful.

See cib documentation for details about the cib string constant class.

cts_t

Sometimes it is useful to wrap a ct_string in a type to preserve compile-time properties. For this, there is cts_t and a corresponding user-defined literal.

using namespace stdx::literals;

constexpr auto s = "hello"_ctst;
// s is a stdx::cts_t<"hello">

Think of cts_t relating to ct_string as std::integral_constant relates to int.

A cts_t is implicitly convertible to a ct_string, or can be explicitly converted with unary operator+:

using namespace stdx::literals;

template <stdx::ct_string S>
constexpr bool always_true = true;

constexpr auto s = "hello"_ctst;
static_assert(always_true<s>);    // implicit conversion
static_assert(always_true<+s>);   // explicit conversion with +