Question about overloading

Hi all,

Suppose I have a function in which I can enter up to 100 uint_8 variables to execute a particular process that requires this amount of variables. The user enters randomly generated values for the ints used in the function, and the number of vars can change randomly as well (for some reason)
If I want to create a library to call upon this method using method overloading, is there a way to define the overloading of the same int types more efficiently than writing 100 overload methods, each adding one more variable every time? how would this be achieved?

Thanks
-EZ

1 Like

If you mean 100 parameters to a function, this is a spectacularly bad idea.
For how to implement a function with a variable number of arguments, see here: C - Variable Arguments

let the user hand over a reference to an array and the array size. --> two parameters.

1 Like

I second the array and size solution, for example that’s what the write() functions offers. It has two versions, one with a single byte and one with a pointer to the first byte and the number of bytes you want to send. (And actually a third one for cStrings).
That’s a very frequent approach to this need.

Using variadic is a possibility too, it would only make sense when the data cannot be easily arranged in an array (for example see how printf() works with support for multiple data types)

Thanks @cedarlakeinstruments. In the note you linked, it stipulates that the user needs to specify the total number of arguments at the beginning of the list. In this case :

   printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
   printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
}

But I don't want the user to explicitly have to state the number of arguments before writing arguments to the function. That is going to be hidden in the code of the library. The user, can write any random number of ints he wants, from 1 to 100 and pass them as arguments, like this

   func(1,2,3);
   func(11,89,72,35);

And the library will accommodate and format to other special functions to pass on further; the user didn't have to explicitly state the number of ints of arguments to be used.

It seems that overloading differs from the C-variable arguments in this regard?

Ok so it seems that the only way to reduce the library .h header and .cpp implementation for an overloaded function with a high number of arguments of the same type is to force the user of the library to specify array size and a predefined array formatting for the function, whereas writing the 100 overloaded functions basically consumes more time and memory but in the end, it allows the user to just enter whatever number of arguments he desires (within the scoped range) for the function with no need to specify the number of arguments. Am I correct on this assumption?

a)
why not?
a call like

funct(array, sizeof(array)/sizeof(array[0]));

is commonly used.

but honestly ... who should do a call with 100 parameters. or 99, or 101.

b)
read again the post of @J-M-L very carefully.

c)
For me this sounds like a XY Problem.
What do you want to achieve really?

Add to your explanation three examples sketches

  • one with the call of 3 parameters
  • one with the call of 42 parameters
  • one with the call of 100 parameters

Just 3 working examples to see what the code might look like.

With sum() you could use default arguments, but to calculate the average that would not work...

int sum(int a1, int a2=0, int a3=0) {
   return a1+a2+a3;
}

But this seems like a stupid idea for 100 arguments..
And of course using an array or a vector would be far better...

No you could also use templates possibly and recursion if that's suitable. I’m on my iPhone at the moment but will try to share an example later on

1 Like

Yes, C and C++ differ here. C++ allows the same function name to be defined for different sets of arguments using "name mangling", a trick in the background which renames the duplicate function names. In C, it is not possible to distinguish between functions which have the same name depending on the argument signature.

Are you designing a library so that it users can do something like this ?:

uint16_t mySum = genericFunction( "sum" , 15, 255, 31 ) ;
uint8_t  myAv  = genericFunction( "average" , 33, 255, 20, 19 ) ;

or can you give some more concrete examples of what you are trying to achieve ?

You can use a vector as an argument.
Vectors know their own size...
So it can have as many ints as you want (within limits of RAM.
No overloading needed...

1 Like

would something like this help? (recursion + template)

template <typename T> T calculateSum(T a) {
  return a;
}

template <typename T> T calculateSum(T a, T b) {
  return a + b;
}

template <typename T, typename... Targs> T calculateSum(T first, Targs... rest) {
  return calculateSum(first, calculateSum(rest...));
}


template <typename T> size_t calculateCount(T a) {
  return 1;
}

template <typename T> size_t calculateCount(T a, T b) {
  return 2;
}

template <typename T, typename... Targs> size_t calculateCount(T first, Targs... rest) {
  return 1 + calculateCount(rest...);
}

template <typename T, typename... Targs> double calculateAverage(T first, Targs... rest) {
  size_t n = calculateCount(first, rest...);
  T s = calculateSum(first, rest...);
  return double(s) / n;
}

void setup() {
  int sum;
  double avg;

  Serial.begin(115200);  Serial.println();
  Serial.println(F("-------------------"));
  Serial.print(F("sum: ")); Serial.println(calculateSum(1));
  Serial.print(F("sum: ")); Serial.println(calculateSum(1, 2));
  Serial.print(F("sum: ")); Serial.println(calculateSum(1, 2, 3));
  Serial.print(F("sum: ")); Serial.println(calculateSum(1, 2, 3, 4));

  Serial.println(F("-------------------"));
  Serial.print(F("average: ")); Serial.println(calculateAverage(1, 2, 3));
  Serial.print(F("average: ")); Serial.println(calculateAverage(1, 2, 3, 4));
}

void loop() {}

the Serial monitor will show

-------------------
sum: 1
sum: 3
sum: 6
sum: 10
-------------------
average: 2.00
average: 2.50

regarding your question:

➜ almost correct, the unused function won't be part of the code. (say you wrote 100 functions but use only the ones with 2, 5 and 25 parametrers, the 97 others won't be part of the final generated code)

I don't want to waste your time as long as the TO doesn't show his examples.
But a

  Serial.print(F("ovr: ")); Serial.println(calculateSum(32000, 32000));

will produce an overflow due to the used templated data types.
ovr: -1536

Here is a little trick that gets rid of the size parameter.

template <size_t n>
void f(int (&arr)[n]) {
  for (size_t i = 0; i < n; i++) {
    // Do something with `arr[i]`.
  }
}

Usage:

int arr[10];
f(arr);

indeed, that's by design of course :slight_smile:

I guess you need to do something like this

Serial.println(calculateSum(32000ul, 32000ul));

The question is:

can I write a function that accepts any number of 8-bit data values from 1-100 (hypothetical) as arguments, without any other argument, and be processed by the same function on the library, without using overloading on the library function?

I don't want to create the XY problem here, so if you have your own approach let me know.

I was writing a lengthy answer to your questions, but then I realize I have been relying only on individual values for the arguments when I really could use an array but without asking the user to pass the array length as an argument.

Let's say that the function coded by programmer X says

CoolStuff::UserFunc(23,45,12,3,28,77,98,15,6,37,4);

Now, inside the library:

uint8_t UserFunc(originalArray[]){
               
          uint8_t formattedArray[sizeof(originalArray)];

              for(int i = 0; i <= sizeof(originalArray); i++)
                  {
                     //Process stuff inside the array
                     //place modified data inside the formattedArray[]
                 } 
             return formattedArray;
}

If it is possible to pass an array as argument and extract its size using sizeof(), then the user does not need to pass the array size value in the arguments, only the values. That would eliminate the need for overloading.

Is this a correct approach programming-wise? sorry if I don't make myself clear.

Thanks for your insight @6v6gt . Well, It is a function that accepts a number of arguments that will be simplified based on some complex rules and re-arranged into an array, so basically, the input is a list of 8-bit values that get simplified and re-arranged, then returned as an array. So in the end 80 numbers could become 40 inside an array return.

As you mention, "name mangling" is not allowed, and it seems that passing an array may require the size of the array to be specified by the user (which is something I want to avoid) therefore I figured method overloading would be the only way to achieve it, but I reckon it looks highly inefficient to use for lengthy arg lists of the same type . I was wondering if an array could be passed as argument and extract its size inside the function using sizeof(), but I have no tried it yet.
Maybe you have tried it before?

@build_1971 this approach sounds great, but I have never worked with vectors. I'll take a look at the corresponding literature. Let me know if you have an easy-to-understand example link for guidance.

thanks!

Thank you @jfjlaros . It seems for usage, you still need to declare an array in advance and pass it to the function. In this case, the objective is to pass 8-bit int arguments to the lib function directly (1 to 100) without declaring arrays or anything else beforehand.

f(23,4,56,7,9,67,8,45.....);

Hi @J-M-L .

This looks a very elegant solution, but I have never used Templates. Please allow me to take a look to some other answers and I'll get back to this one, which looks like it might work fine.

➜ almost correct, the unused function won't be part of the code. (say you wrote 100 functions but use only the ones with 2, 5 and 25 parametrers, the 97 others won't be part of the final generated code)

I agree to that, and the more I look into it, the less I like the overloading approach...looks like a waste of time. Thanks for pointing it out.