Let's say you call a function like this:
someFunc( some_int, some_float, false, "whatever text");
This doesn't look good but if alternatively I pass these by a struct / class, it won't look much better, since I will make up the struct on-the-fly like I do with function parameters.
someFunc( FuncParameters( some_int, some_float, false, "whatever text"));
Even if the struct has the parameter names in it's definition, I don't see those when I call it's constructor.
I can do this instead:
FuncParameters func_parameters;
func_parameters.some_int_data = some_int;
func_parameters.some_float_data = some_float;
func_parameters.some_text_data = "whatever text";
someFunc(func_parameters);
But if I forget the bool-data like above, then nothing will complain about it.
So why do people say that "always pass parameters in structure if there are more than X number of parameters? What am I missing?
Using structures instead of separate parameters has several advantages:
soldier.speed = 3.2;) are clearer than simply passing 3.2. This applies even more to bool literals and function calls such as CreateSoldier(3.2, true, false, true).There are also some things to keep in mind:
SetSpeed(&soldier, 3.2)).I think one main reason is code readability. You can read in CppCoreGuidelines
Keep the number of function arguments low
Reason Having many arguments opens opportunities for confusion. Passing lots of arguments is often costly compared to alternatives.
...
Grouping arguments into "bundles" is a general technique to reduce the number of arguments and to increase the opportunities for checking.
Example
void f(int* some_ints, int some_ints_length); // BAD: C style, unsafeversus
void f(gsl::span<int> some_ints); // GOOD: safe, bounds-checked
With your example
someFunc(10,20,true,"foo");
is more confusing than:
struct SomeFuncParameters
{
int max_iterations = 100;
float epsilon = 1.e-6;
bool reinit = true;
std::string name = "";
};
void someFunc(const SomeFuncParameters& parameters) {}
int main()
{
// Variation 1
//
someFunc(SomeFuncParameters());
// Variation 2
//
someFunc(SomeFuncParameters{.max_iterations = 10,
.epsilon = 1e-4,
.reinit = false,
.name = "my name"});
// Variation 3
//
SomeFuncParameters someFuncParameters;
someFuncParameters.epsilon = 1e-10;
someFunc(someFuncParameters);
}
even if you have to write a longer code.
Also note that when you use a struct to store parameters you can easily define parameter default values. You also have less code to modify if you want to add or remove some parameters as the call sites like:
someFunc(SomeFuncParameters());
someFunc(someFuncParameters);
won't be affected.
I also wrote a small C++17 lib for named optional arguments that can maybe interest you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With