gz-cpp-util 1.3
A c++20 library containing various utilities
String conversion

About

This library provides utility for string conversion, from and to std::string. The string utility is split into 3 files:

There also three important concepts, ConvertibleToString, ConstructibleFromString and StringConvertible which are used in the logger and the settings manager to log and store types.

If you want to use your own types with one of these, you can easily write your own string conversion function for your custom types.

Converting to string

You can use the gz::toString() function to turn certain types into strings. Concepts are used to determine the correct overload of the function.

The concept ConvertibleToString is satisfied for types that can be converted to string using gz::toString().

Types convertible to string

The toString() function is implemented for these types (non-exhaustive list of examples in braces)

  1. Any string-like type: eg. std::string, std::string_view { std::string, std::string_view }
  2. Any type that is accepted by the constructor of std::string() { char, const char* }
  3. Any type that works with std::to_string() { int, double, bool ... }
  4. Any type that has a `toString() const` or `to_string() const` member that returns a string
  5. Any type where a <tt>std::string toString(const T&)</tt> overload exists in global namespace
  6. Any of the following (the mentioned members have to satisfy one of 1-5)
    • Any type with t.x and t.y
    • Any type with t.x, t.y, t.z
    • Any type with t.x, t.y, t.z and t.w
    • Any type with t.width, t.height
    • Any type with t.width, t.height, t.depth
  7. Any of 1-6, but "behind" a pointer
  8. Any type that has a forward_iterator which references any one of 1-7 { std::vector<int>, std::list<float> }
  9. Any type with t.first and t.second members which satisfy one of 1-8 { std::pair<int, const char*> }
  10. Any type that has a forward_iterator which references 9 { std::map<unsigned long, std::vector<bool> }

Construct from string

You can use the gz::fromString() function to create certain types from a string.

The concept ConstructibleFromString is satisfied for types that can be constructed from a string with gz::fromString().

When constructing something from a string, there is of course the problem that errors occur at runtime when the string is unsuitable for construction. In this case, the fromString functions from this library throw an exception (either InvalidArgument, or std::invalid_argument / std::out_of_range).

Overloading the string conversion functions

Overload for toString

If you want your custom type to be convertible to string, you have different options. You can either add an toString() const member to your class or overload std::string toString(const T&) in global or gz namespace. Example for a class called Custom:

std::string toString(const Custom& c) {
std::string s;
...
return s;
}
std::string toString(const T &s)
Declaration of toString in global namespace, so that concepts can use it.

Overload for fromString

Writing an overload for fromString needs a little bit more boiler plate. Since fromString is a templated function, you need to declare it as such. The function declaration in this library uses a concept so that it is only declared for the types that are actully implemented. Example for a class called Custom:

// declare as template, but only for Custom
template<std::same_as<Custom> T>
Custom fromString(const std::string& s);
// instantiation/definition, but only for Custom
template<>
Custom fromString<Custom>(const std::string& s) {
...
return Custom(...);
};
T fromString(const std::string &s)
Declaration of fromString in global namespace, so that concepts can use it.

Notes

You should write your function so that the output of one can be used as input of the other. In other words:

Custom c1;
Custom c2 = fromString(toString(c1));
assert(c1 == c2);

SettingsManager expects the strings from toString() to be a single line. If it has multiple lines, it will not load it correctly when loading from a file.

Troubleshoting

My custom overloads are not recognized

To satisfy the concept(s) ConvertibleToString/ConstructibleFromString/StringConvertible, any overload must be visible to the compiler when the concept is processed, so you have to declare it before including string/to_string.hpp/string/from_string.hpp (which may also be included by string/conversion.hpp, settings_manager.hpp and log.hpp). To ease troubleshooting the include order, string/to_string.hpp/string_from_string.hpp each define the macro GZ_UTIL_STRING_CONCEPTS, so you can place an assertion like this before declaring your overloads:

#ifdef GZ_UTIL_STRING_CONCEPTS
static_assert(false, "gz-util/string/conversion.hpp must not be included before this file!");
#endif

I want to use the toString/fromString functions from this library in my custom overloads

Separate the declaration from the definition:

// file.hpp
// do not include any file from <gz-util/string/...>
// declare your overloads:
class Custom {
std::string toString() const;
}
// or
std::string toString(const Custom& c);
template<std::same_as<Custom> T>
T fromString(const std::string&)
// file.cpp
#include "file.hpp"
#include <gz-util/string/conversion.hpp>
// define your functions
std::string Custom::toString() const {
...
}
// or
std::string toString(const Custom& c) {
...
}
template<>
Custom fromString(const std::string& s) {
...
}

I want to write the toString() for my Vector types myself

Define the macro GZ_TO_STRING_NO_VECTORS before including <gz-util/string/to_string.hpp>. This disables all overloads for Vector and Extent classes.

Todo:
Implement fromString for ranges that hold ConstructibleFromString types

Converting integers to/from strings with different base

The functions toHexString(), toOctString() and toBinString() can be used to get a string of an integers representation in 16 / 8 / 2 basis.

The functions fromHexString<T>(), fromOctString<T>() and fromBinString<T>() can be used to get an integer from a string representation of an integer in 16 / 8 / 2 basis. These function can throw std::invalid_argument and std::out_of_range.

Note
toHexString() and toOctString() do not work well with (unsigned) char ((u)int8_t).