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.
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 +