Skip to content

Functions

Hannes Hauswedell edited this page Apr 12, 2017 · 1 revision

We distinguish between

  • member functions of a class or struct, also called methods
  • free functions in the scope of namespace (not class/struct), also called global functions

First read the Chapter on Functions in the CoreGuidelines!

Function arguments and return types

Basics:

  • in-parameters are parameters that are only read from in the function
    1. shall be type variable (copy) if you want a copy inside function
    2. shall be type const variable for small builtins, i.e. mainly arithmetic types
    3. shall be type const & variable for specific class types
    4. shall be type && variable for parameters with type deduction (templated parameters)
    5. shall be type const & /**/ for type-only parameters / tags
  • in-out-parameters are parameters that are both read from, and written to
    • shall be & in all cases
  • out-parameters are parameters that are only written to
    • shall be return values (if multiple return values, put them in std::tuple<>)
    • in case you need to specialize over the type of the out-parameter, treat it as in-out

Reasons:

  • in-parameters:
    1. If you plan on copying the argument inside your function, you should instead copy it in the signature, because this enables usage of the move-constructor, saving the copy operation if the function is passed a temporary. It also eases writing exception-safe code. [See also the copy and swap idiom]
    2. The specified types are smaller than references.
    3. Don't copy, since you don't have to; use const protection, because you can.
    4. Since the type before the && is subject to type deduction, the type is not an rvalue reference, but a forwarding reference. This implies that it can resolve to &, && and also const & so it is more generic than only const &. This is especially important for objects that are not const-iterable like certain ranges.
    5. If you are not going to use an argument's value, omit the variable to enable compiler optimization.
  • out-parameters
    1. Since C++17 there is guaranteed copy elision on return values so we don't need to worry about it and just return. There are also so called structured bindings to easily access the return values.

Function argument number and order

Number of arguments:

  • should be ≀ 5
  • use ranges instead of individual begin + end iterators (if applicable)
  • use std::pairs and std::tuples instead of individual value parameters (if applicable)
  • use traits instead of individual type parameters (if applicable)

There is no strict policy on the order of arguments (e.g. "output before input"), use the following guideline:

  1. "data arguments" (e.g. a string that is being processed)
    • "input data arguments" come before "output data arguments" (but often the latter are return values anyway)
  2. "option arguments" (e.g. how the string shall be processed)
  3. type-only "option arguments" (e.g. tags or traits)

Also keep in mind that if you want to default some parameters, they need to be at the end. Execution policies are a special case and always come first.

Design your function signature so that there aren't too many possible interfaces, ideally 1-2, but not more than 3-5 (with and without defaults).

Function templates

  1. always constrain your template parameters!
  2. choose the least-constrained concept that works for your algorithm
  3. but enforce all the requirements that you actually have!
  4. use forwarding reference && instead of const &, also for read only parameters (see above)

Examples for 2.:

  • do not require a container_concept if a forward_range_concept is sufficient
  • do not require a random_access_sequence_concept if a sequence_concept is sufficient

Examples for 3.:

  • if you do require random access, make sure that you include the corresponding requirements!

Member functions

TODO?

Free functions

TODO?

Clone this wiki locally