NO

Author Topic: Variadic Overloading Solved?  (Read 8232 times)

sweetname

  • Guest
Variadic Overloading Solved?
« on: January 26, 2015, 04:05:18 PM »
After a bit of research and a lot of mucking about I've come up with this:

Code: [Select]
#include <stdio.h>

// Variadic Function Overloading:

#define VOID "__variadic_VOID__"

#define variadic_count(...) variadic_count_(__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0)
#define variadic_count_(_6, _5, _4, _3, _2, _1, count, ...) count

#define variadic_token(func, ...) variadic_token_(func, variadic_count(__VA_ARGS__))
#define variadic_token_(func, count) variadic_token__(func, count)
#define variadic_token__(func, count) func ## _ ## count

#define variadic(func, ...)\
do {\
if (#__VA_ARGS__ == "\"__variadic_VOID__\"")\
{\
variadic_token__(func, 0)();\
}\
else\
{\
variadic_token(func, __VA_ARGS__)(__VA_ARGS__);\
}\
} while (0)

// Usage:

#define somefunction(...) variadic(somefunction, __VA_ARGS__)

#define somefunction_0()\
do {\
printf("somefunction_0(VOID)\n\n");\
} while (0)

#define somefunction_1(x)\
do {\
printf("somefunction_1(x = %i)\n\n", (x));\
} while (0)

#define somefunction_2(x, y)\
do {\
printf("somefunction_2(x = %i, y = %i)\n\n", (x), (y));\
} while (0)

int main(int argc, char* argv[])
{
//somefunction(); ERROR
somefunction(VOID);
somefunction(1);
somefunction(11);
somefunction(2, 3);
//somefunction(1, 2, 3); ERROR

printf("\n\n");
return 0;
}

Essentially, it allows for a distinction between zero and one arguments via the special token VOID.  It works unless the variadic function/macro is passed the string literal defined by VOID as a sole argument.  In this case, only a call of somefunction("__variadic_VOID__"); will cause unexpected behavior; passing a variable with the same value as the string literal does not cause unexpected behavior.

While the provided code only works for 0-6 arguments, it can be modified to work with a greater number of arguments.

I'm curious, however, as to whether or not if ("blah" == "blah") {doSomething();} is optimized to doSomething(); by the compiler?  Or does the pointer comparison occur at runtime?  If it is optimized away, then I think this code snippet effectively allows for easy variadic overloading of functions/macros with virtually no downside...

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Variadic Overloading Solved?
« Reply #1 on: January 26, 2015, 05:06:58 PM »
The comparison of constant values is preevaluated in the compiling phase and only the used part of the code is emitted.
The part of the code that is not used is normally referenced as 'dead code', and it is removed as basic optimization.
There is also a misunderstanding abou the preprocessor, many think that it can execute math and string computation, but, unless in very limited way, it don't do this. The preprocessed expressions are fed to the compiler that makes the real computation and remove the unwanted code as 'dead code'.
if you write:
Code: [Select]
#define NUM_OF_BITS 4
#if sizeof(struct a) > (1<<NUM_OF_BITS))
some code
#else
Other code
#endif
It will be passed to the compiler, after preprocessing as:
Code: [Select]
if (sizeof(struct a) > (1<<4))
{
   do something
}
else
{
    do else
}

Then the compiler will calculate the sizeof struct and make comparison between two constants, the sizeof and 1<<4, and will eliminate the parte of the code that will never be executed.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

sweetname

  • Guest
Re: Variadic Overloading Solved?
« Reply #2 on: January 26, 2015, 05:17:05 PM »
Thanks!

I'm still curious, however, as to whether or not if ("someStringLiteral" == "someStringLiteral") {doSomething();} is optimized to doSomething(); by the compiler?  I really need to know about this very specific case of comparing the pointers of two string literals.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Variadic Overloading Solved?
« Reply #3 on: January 26, 2015, 05:22:22 PM »
Very simple.
Write a minimal code, compile with debug informations on.
Now open debugger and when you are on your code switch to assembly view  ;).
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

sweetname

  • Guest
Re: Variadic Overloading Solved?
« Reply #4 on: January 26, 2015, 05:37:48 PM »
Sorry, I am new to Pelles C.    :'(

I tried to do what you suggested, but I'm not sure what to be looking for.  Also, I'm not sure if I compiled with debug information on correctly...

Could you provide me with a more detailed explanation of how to tell?

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: Variadic Overloading Solved?
« Reply #5 on: January 26, 2015, 05:51:14 PM »
Look at the help file and search the forum, this is a very often asked question...
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

sweetname

  • Guest
Re: Variadic Overloading Solved?
« Reply #6 on: January 26, 2015, 10:33:50 PM »
Aha!

I used the following code:

Code: [Select]
#include <stdio.h>

int main(int argc, char* argv[])
{
int x = 10;
if ("blah" == "blah")
{
x = 11;
}

printf("x = %i\n\n", x);

return 0;
}

And when I viewed the disassembly it appears that no conditional branching is performed, is this correct?  So may I safely assume that it will always be the case that a comparison between two string literals will be optimized out?
« Last Edit: January 26, 2015, 11:08:57 PM by sweetname »

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: Variadic Overloading Solved?
« Reply #7 on: January 26, 2015, 11:40:04 PM »
And just to be clear, Pelle's C is just that, a C11 C compiler, not a C++ compiler. Overloading does not work in C to begin with...

Ralf

sweetname

  • Guest
Re: Variadic Overloading Solved?
« Reply #8 on: January 26, 2015, 11:48:00 PM »
And just to be clear, Pelle's C is just that, a C11 C compiler, not a C++ compiler. Overloading does not work in C to begin with...

Ralf

Well...the code I provided allows overloading based on number of parameters in Pelles C.

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: Variadic Overloading Solved?
« Reply #9 on: January 27, 2015, 01:05:34 AM »
And just to be clear, Pelle's C is just that, a C11 C compiler, not a C++ compiler. Overloading does not work in C to begin with...

Ralf

Well...the code I provided allows overloading based on number of parameters in Pelles C.
Well, not really, you are just using the VA_ARGS feature. That isn't really "overloading"...

Ralf

sweetname

  • Guest
Re: Variadic Overloading Solved?
« Reply #10 on: January 27, 2015, 02:29:50 AM »
And just to be clear, Pelle's C is just that, a C11 C compiler, not a C++ compiler. Overloading does not work in C to begin with...

Ralf

Well...the code I provided allows overloading based on number of parameters in Pelles C.
Well, not really, you are just using the VA_ARGS feature. That isn't really "overloading"...

Ralf

"In some programming languages, Function overloading or method overloading is the ability to create multiple methods of the same name with different implementations. Calls to an overloaded function will run a specific implementation of that function appropriate to the context of the call, allowing one function call to perform different tasks depending on context." - Wikipedia Entry (Function overloading)

The code I provided allows for calls to a function to be dispatched based on the number of arguments.

Simply register your function as variadic with:

Code: [Select]
#define somefunction(...) variadic(somefunction, __VA_ARGS__)
Next append "_X" to each version of the overloaded function where X is the number of arguments that the version utilizes.

That's it.

Suppose you had the following:

Code: [Select]
#define somefunction_0()\
do {\
printf("ZERO!\n");\
} while (0)

#define somefunction_1(x)\
do {\
printf("x = %i\n", (x));\
} while (0)

#define somefunction_2(x, y)\
do {\
printf("%c%c\n", (x), (y));\
} while (0)

Then you could use your function like so:

Code: [Select]
somefunction(VOID); // ZERO!
somefunction(1); // x = 1
somefunction(11); // x = 11
somefunction('a', 'b'); // ab
« Last Edit: January 27, 2015, 02:41:42 AM by sweetname »