* [F.17: Use a `not_null<T>` to indicate "null" is not a valid value](#Rf-nullptr)
* [F.18: Use a `span<T>` or a `span_p<T>` to designate a half-open sequence](#Rf-range)
* [F.19: Use a `zstring` or a `not_null<zstring>` to designate a C-style string](#Rf-string)
* [F.20: Use a `const T&` parameter for a large object](#Rf-const-T-ref)
* [F.21: Use a `T` parameter for a small object](#Rf-T)
* [F.22: Use `T&` for an in-out-parameter](#Rf-T-ref)
* [F.23: Use `T&` for an out-parameter that is expensive to move (only)](#Rf-T-return-out)
@ -2219,10 +2218,16 @@ If you have multiple values to return, [use a tuple](#Rf-T-multi) or similar mul
**For an "in-out" parameter:** Pass by non-`const` reference. This makes it clear to callers that the object is assumed to be modified.
**For an "input-only" value:** If the object is cheap to copy, pass by value.
Otherwise, pass by `const&`. It is useful to know that a function does not mutate an argument, and both allow initialization by rvalues.
Otherwise, pass by `const&` which is always cheap. Both let the caller know that a function will not modify the argument, and both allow initialization by rvalues.
What is "cheap to copy" depends on the machine architecture, but two or three words (doubles, pointers, references) are usually best passed by value.
In particular, an object passed by value does not require an extra reference to access from the function.