README.md
5639d4a5
 # [`cxx-str`][]
 
 A [C++11][] [`std::string`][] [macro][] library.
 
c3e0ef8c
 If [C++20][] is avaiable, [`std::format`][] and [`std::source_location`][] may
 be more appropriate. If [C++23][] is available, [`std::stacktrace`][] may be
 more appropriate.
 
5639d4a5
 [`cxx-str`]: https://git.rcrnstn.net/rcrnstn/cxx-str
 [C++11]: https://en.wikipedia.org/wiki/C++11
 [`std::string`]: https://en.cppreference.com/w/cpp/string/basic_string
 [macro]: https://en.cppreference.com/w/cpp/preprocessor/replace
c3e0ef8c
 [C++20]: https://en.wikipedia.org/wiki/C++20
 [`std::format`]: https://en.cppreference.com/w/cpp/utility/format/format
 [`std::source_location`]: https://en.cppreference.com/w/cpp/utility/source_location
 [C++23]: https://en.wikipedia.org/wiki/C++23
 [`std::stacktrace`]: https://en.cppreference.com/w/cpp/utility/basic_stacktrace
 
 ## Usage
 
 Note that macros can result in unintuitive behavior.
 
 Looking at the [source][] and [test][] is the best way to understand usage.
 
 Throughout, arguments are only evaluated once. When [lambda][]s are defined and
 immediately called behind the scenes, values are implicitly [capture][]d by
 reference. The only lambda that implicitly captures by value is
 `STR_FUNC(VALUE)`.
 
 Include the header:
 
 ```cpp
 #include <str.hpp>
 ```
 
 There are a few different categories of functionality:
 
 -   Easy access to [`std::ostringstream`][]'s [`operator<<`][] and [`str()`][].
     The `VALUE` expressions below can contain several values joined with `<<`.
 
     `STR(VALUE)` produces a string.
 
     `STR_FUNC(VALUE)` produces a [lambda][], which implicitly [capture][]s by
     value, and returns a string. Useful for lazy evaluation of costly string
     operations. For good performance, make sure the standard library can
     perform Small String Optimization ([SSO][]) (and if used with
     [`std::function`][], Small Object Optimization ([SOO][])).
 
     `STR_JOIN(JOIN, ITERATOR, VALUE, ...)` makes the variable name `ITERATOR`
     available in the `VALUE` expression, and joins the corresponding non-empty
     (as interpreted by `STR(VALUE)`) elements of `...` with `JOIN`.
 
     `STR_JOIN_INIT(JOIN, ITERATOR, VALUE, TYPE, ...)` forwards to
     `STR_JOIN(JOIN, ITERATOR, VALUE, ...)`, passing
     [`std::initializer_list`][]`<TYPE>`[`__VA_ARGS__`][]`)` as the last
     argument. Notice the lack of braces, they have to be supplied manually.
 
     `STR_JOIN_INITSTR(JOIN, ITERATOR, VALUE, ...)` forwards to `STR_JOIN_INIT`
     with `std::string` as the `TYPE` argument.
 
 -   Easy access to the stringifying and concatenating [`#` and `##`
     operators][] to help map constants to strings.
 
     `STR_CASE(CASE)` uses `case` and `return` statements: `case (CASE): return
     (#CASE);`.
 
     `STR_COND(VALUE, CASE)` uses the [conditional operator][]: `((VALUE) ==
     (CASE)) ? (#CASE) :`.
 
     `STR_INIT(CASE)` uses [list initialization][]: `{(CASE), (#CASE)},`.
 
     `STR_ARGS(ARG)` expands to `ARG, #ARG`.
 
     `STR_ARGS_PREFIX(PREFIX, ARG)` expands to `PREFIX##ARG, #ARG`.
 
 -   Easy access to source file and line.
 
     `STR_HERE(VALUE)` joins [`__FILE__` and `__LINE__`][] and [`__func__`][]
     with `":"`, and appends `": "` and the given argument to produce a string.
 
 -   Easy handling to ([nested][]) [`std::exception`][]s, which contain strings
     accessible through the [`what()`][] method.
 
     `STR_EXCEPTION` can be defined to control what exceptions are thrown by the
     macros below. If it is not defined, [`std::runtime_error`][] is used.
 
     `STR_THROW(VALUE)` [`throw`][]s a `STR_EXCEPTION` initialized with
     `STR(VALUE)`.
 
     `STR_THROW_ERRNO()` calls `STR_THROW` with the argument
     `std::generic_category().message(errno) << "."`.
 
     `STR_RETHROW(VALUE)` calls [`std::terminate`][] if called outside a
     [`catch`][] block. Otherwise, `STR_THROW`s `VALUE` followed by the
     [`what()`][] of the current exception (so it is appropriate to include a
     separator manually) if it is a (derives from) [`std::exception`][],
     otherwise simply rethrows the current exception.
 
     `STR_NESTED_THROW(VALUE)` calls [`std::throw_with_nested`][] on a
     `STR_EXCEPTION` initialized with `STR(VALUE)`.
 
     `STR_NESTED_THROW_ERRNO()` calls `STR_NESTED_THROW` with the argument
     `std::generic_category().message(errno) << "."`.
 
     `STR_NESTED_WHAT(JOIN, EXCEPTION)` joins the strings returned by the
     (optionally) [nested][] [`std::exception`][]-based `EXCEPTION`'s
     [`what()`][] methods with `JOIN`, and returns the resulting string.
 
 [source]: include/str.hpp
 [test]: tests/str.cpp
 [lambda]: https://en.cppreference.com/w/cpp/language/lambda
 [capture]: https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture
 [`std::ostringstream`]: https://en.cppreference.com/w/cpp/io/basic_ostringstream
 [`operator<<`]: https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt
 [`str()`]: https://en.cppreference.com/w/cpp/io/basic_ostringstream/str
 [SSO]: https://en.cppreference.com/w/cpp/language/acronyms
 [`std::function`]: https://en.cppreference.com/w/cpp/utility/functional/function
 [SOO]: https://en.cppreference.com/w/cpp/language/acronyms
 [`std::initializer_list`]: https://en.cppreference.com/w/cpp/utility/initializer_list
 [`__VA_ARGS__`]: https://en.cppreference.com/w/cpp/preprocessor/replace
 [`#` and `##` operators]: https://en.cppreference.com/w/cpp/preprocessor/replace#.23_and_.23.23_operators
 [list initialization]: https://en.cppreference.com/w/cpp/language/list_initialization
 [conditional operator]: https://en.cppreference.com/w/cpp/language/operator_other#Conditional_operator
 [`__FILE__` and `__LINE__`]: https://en.cppreference.com/w/c/preprocessor/line
 [`__func__`]: https://en.cppreference.com/w/cpp/language/function#func
 [`#ifndef`]: https://en.cppreference.com/w/cpp/preprocessor/conditional
 [`NDEBUG`]: https://en.cppreference.com/w/c/error/assert
 [nested]: https://en.cppreference.com/w/cpp/error/nested_exception
 [`std::exception`]: https://en.cppreference.com/w/cpp/error/exception
 [`what()`]: https://en.cppreference.com/w/cpp/error/exception/what
 [`std::runtime_error`]: https://en.cppreference.com/w/cpp/error/runtime_error
 [`throw`]: https://en.cppreference.com/w/cpp/language/throw
 [`std::terminate`]: https://en.cppreference.com/w/cpp/error/terminate
 [`catch`]: https://en.cppreference.com/w/cpp/language/try_catch
 [`std::throw_with_nested`]: https://en.cppreference.com/w/cpp/error/throw_with_nested
 
 ## Test output
 
 The [test][] outputs:
 
 ```
 0x3
 0x3
 "first", "", "third"
 first, third
 
 first
 unknown
 third
 
 /path/to/cxx-str/tests/str.cpp:96: Hello from here
 
 Failed to do outer:
 Failed to do inner:
 Expected this, got that.
 ```
bd2b9a05
 
1af83b2a
 ## Building
 
 See [`BUILDING.md`][].
 
 [`BUILDING.md`]: BUILDING.md
 
bd2b9a05
 ## License
 
 Licensed under the [ISC License][] unless otherwise noted, see the
 [`LICENSE`][] file.
 
 [ISC License]: https://choosealicense.com/licenses/isc/
 [`LICENSE`]: LICENSE