Using a struct to replace the parameter list of a function "f()" makes sense when:
- You pass all the arguments by value, or you easily could.
- The struct itself can be a simple aggregate (i.e. supports designated ".member = value" initializer lists in c++20)
- Your current function signature has many parameters of the same type, so using designated initializers w/ a struct would be way clearer code for callers.
It's an even better choice when you also have:
- 1 or more defaulted or optional parameters, which can become
std::optional<> and defaulted fields of the struct. Especially if you have to handle some of these cases by overloading "f()".
- You can identify other places in the code where this same struct is useful.
It is a BAD idea when your function "f()" has any of these properties:
- "inout" parameters you can't easily refactor away.
- Parameters that either can't be copied or are expensive to copy, since using a simple aggregate struct means you'd be copying them all at every call site. Note that plain old pointers ARE cheap to copy, so this really means const reference parameters like large chunks of text in a
const std::string&.
For example, it makes sense to change this function to take a struct:
bool setVersion(int major, int minor, int patch, int build=0);
Becomes:
struct Version{
int major;
int minor;
int patch;
int build;
}
bool setVersion(Version ver);
And a caller can now do (c++20):
setVersion({.major = 5, .minor = 1, .patch = 2, .build = 101});
which is basically named parameters, even though C++ doesn't technically have that feature.
However, for something like this it makes zero sense to turn that parameter list into a struct:
int parseToInt(const std::string& str, int defaultValue, bool& successful);
You've only got 3 parameters, which are totally distinct types (so the compiler WILL catch out-of-order params at call sites) and one is an 'inout' return. Converting that parameter list into a struct is just going to make a bad situation way, way worse for both your callers & performance.