conststr 0.2.1
Loading...
Searching...
No Matches
The conststr libray

Operate strings in constant context.

Basic usages

Create constant strings

#include "conststr.hpp"
constexpr auto str = cstr("hello world!");
Main header file for the constant string type.
String type that can be evaluated in a constant context.
Definition: conststr.hpp:657

or use user-defined string literal (recommended):

#include "conststr.hpp"
using namespace conststr::literal;
constexpr auto str = "hello world!"_cs;
Define string literal suffix.
Definition: conststr.hpp:1953

The above includes and usings are omitted in subsequent examples.

Print strings

The operator<<(std::ostream &, const cstr &) has been overloaded, so:

constexpr auto str = "hello world!"_cs;
std::cout << str << std::endl;

Compare strings

The conststr::cstr instances are compared in lexicographic order:

static_assert("hello"_cs > "hell"_cs);

Concatenate strings

constexpr auto hello = "hello"_cs;
constexpr auto world = "world"_cs;
constexpr auto msg = hello + ' ' + world + '!';
// or
constexpr auto msg2 = hello.flatten(" "_cs, world, "!"_cs);
// or
constexpr auto msg3 = flatten(hello, " "_cs, world, "!"_cs);
constexpr auto flatten(const First &first, const Str &...strs)
Flatten multiple strings of different lengths.
Definition: conststr.hpp:1933

Operate strings

Note
In order to maintain the uniformity of APIs, all methods that operate on strings do not modify the string itself, but return the modified string.
constexpr auto str = "hello world!"_cs;
constexpr auto newstr = str.uppercase() // to "HELLO WORLD!"
.pop() // to "HELLO WORLD"
.erase(4) // to "HELL WORLD"
.erase(8) // to "HELL WORD"
.append('?'); // to "HELL WORD?"

Check the document page of conststr::cstr to learn more operating methods.

If you really want to modify the original string, std::transform and functions in the namespace conststr::charutils may be helpful:

#include <algorithm>
namespace charutils = conststr::charutils;
constexpr auto fun() {
auto str = "hello world!"_cs;
std::transform(str.begin(), str.end(), str.begin(),
charutils::replace<'o', 'O'>); // to "hellO wOrld!"
std::transform(str.begin(), str.begin() + 2, str.begin(),
charutils::toupper<char>); // to "HEllO wOrld!"
return str;
}
Some constexpr character operating functions.
Definition: conststr.hpp:345

Convert to view

Warning
cstr can be implicitly converted to its view type, but the implicit conversion of a temporary cstr r-values may result in dangling pointers.

Whenever you need to obtain string view or internal pointer from a cstr r-value, store it to a variable first.

constexpr auto str = func_returns_cstr();
constexpr view_type sv = str;

The view type of cstr defaults to std::basic_string_view<T>. You can choose different view types through the following methods:

#include <span>
constexpr auto s1 = cstr("hello world!", sv<std::span<const char>>);
constexpr auto s2 = "hello world!"_cs.with_view<std::span<const char>>();
constexpr auto sv
String view type selector. Assist in type deduction of cstr.
Definition: conststr.hpp:643

Work with limited reflection

Thanks to the introduction of structured binding, we can implement compile-time reflection of aggregate types based on some tricks.

You can include the header file reflect.hpp to use conststr::cstr with reflection, basically it is a reimplementation of glaze based on conststr::cstr.

In order to get reflection you need to use default-constructible aggregate types, Roughly, this means that the type:

  • no user-declared or inherited constructors,
  • no virtual/private/protected base classes,
  • all members are public,
  • no virtual member functions,
  • default-constructible,
  • no member of reference type (but member of std::reference_wrapper with default initializer is allowed).

For example:

struct MyStruct {
int number;
double decimal;
std::string name;
};

Then you can get the name of its members via reflect::name_of, get the type of its members via reflect::type_of/reflect::type_of_member, or get the reference to object's member via reflect::member_of like the following example:

#include "reflect.hpp"
struct MyStruct {
int number;
double decimal;
std::string name;
};
int main() {
// Get member type of `MyStruct` via index
reflect::type_of<MyStruct, 0> a = 1; // type of `a` is `int`
reflect::type_of<MyStruct, 1> b = 1.f; // type of `b` is `double`
reflect::type_of<MyStruct, 2> c = "hello"; // type of `c` is `std::string`
// Also you can get member type via its name
reflect::type_of_member<MyStruct, "number"> d = 1;
reflect::type_of_member<MyStruct, "decimal"> e = 1.f;
reflect::type_of_member<MyStruct, "name"> f = "hello";
// Get member name via index
std::cout << reflect::number_of_members<MyStruct> << std::endl; // 3 members in `MyStruct`
std::cout << reflect::name_of<MyStruct, 0> << std::endl; // first member is "number"
std::cout << reflect::name_of<MyStruct, 1> << std::endl; // second member is "decimal"
std::cout << reflect::name_of<MyStruct, 2> << std::endl; // third member is "name"
// Get member reference via index ...
MyStruct s;
decltype(auto) numref = reflect::member_of<0>(s);
numref = 100;
std::cout << s.number << std::endl;
// ...or, via its name
decltype(auto) nameref = reflect::member_of<"name">(s);
nameref += "hello world";
std::cout << s.name << std::endl;
return 0;
}
type_of< T, index_of< T, Name > > type_of_member
Get the type of the member by its name.
Definition: reflect.hpp:1908
std::remove_cvref_t< std::tuple_element_t< N, decltype(to_tuple(fake_obj< T >))> > type_of
Type of N-th member of a default-constructible aggregate type T.
Definition: reflect.hpp:1745
Header file of comiple-time reflection support.