Is there any way to achieve function overloading in C? I am looking at simple functions to be overloaded like
foo (int a)
foo (char b)
foo (float c , int d)
I think there is no straight forward way; I'm looking for workarounds if any exist.
Is there any way to achieve function overloading in C? I am looking at simple functions to be overloaded like
foo (int a)
foo (char b)
foo (float c , int d)
I think there is no straight forward way; I'm looking for workarounds if any exist.
Yes!
In the time since this question was asked, standard C (no extensions) has effectively gained support for function overloading (not operators), thanks to the addition of the
_Generic
keyword in C11. (supported in GCC since version 4.9)(Overloading isn't truly "built-in" in the fashion shown in the question, but it's dead easy to implement something that works like that.)
_Generic
is a compile-time operator in the same family assizeof
and_Alignof
. It is described in standard section 6.5.1.1. It accepts two main parameters: an expression (which will not be evaluated at runtime), and a type/expression association list that looks a bit like aswitch
block._Generic
gets the overall type of the expression and then "switches" on it to select the end result expression in the list for its type:The above expression evaluates to
2
- the type of the controlling expression isint
, so it chooses the expression associated withint
as the value. Nothing of this remains at runtime. (Thedefault
clause is optional: if you leave it off and the type doesn't match, it will cause a compilation error.)The way this is useful for function overloading is that it can be inserted by the C preprocessor and choose a result expression based on the type of the arguments passed to the controlling macro. So (example from the C standard):
This macro implements an overloaded
cbrt
operation, by dispatching on the type of the argument to the macro, choosing an appropriate implementation function, and then passing the original macro argument to that function.So to implement your original example, we could do this:
In this case we could have used a
default:
association for the third case, but that doesn't demonstrate how to extend the principle to multiple arguments. The end result is that you can usefoo(...)
in your code without worrying (much[1]) about the type of its arguments.For more complicated situations, e.g. functions overloading larger numbers of arguments, or varying numbers, you can use utility macros to automatically generate static dispatch structures:
(implementation here) So with some effort, you can reduce the amount of boilerplate to looking pretty much like a language with native support for overloading.
As an aside, it was already possible to overload on the number of arguments (not the type) in C99.
[1] note that the way C evaluates types might trip you up though. This will choose
foo_int
if you try to pass it a character literal, for instance, and you need to mess about a bit if you want your overloads to support string literals. Still overall pretty cool though.Leushenko's answer is really cool - solely: the
foo
example does not compile with GCC, which fails atfoo(7)
, stumbling over theFIRST
macro and the actual function call ((_1, __VA_ARGS__)
, remaining with a surplus comma. Additionally, we are in trouble if we want to provide additional overloads, such asfoo(double)
.So I decided to elaborate the answer a little further, including to allow a void overload (
foo(void)
– which caused quite some trouble...).Idea now is: Define more than one generic in different macros and let select the correct one according to the number of arguments!
Number of arguments is quite easy, based on this answer:
That's nice, we resolve to either
SELECT_1
orSELECT_2
(or more arguments, if you want/need them), so we simply need appropriate defines:OK, I added the void overload already – however, this one actually is not covered by the C standard, which does not allow empty variadic arguments, i. e. we then rely on compiler extensions!
At very first, an empty macro call (
foo()
) still produces a token, but an empty one. So the counting macro actually returns 1 instead of 0 even on empty macro call. We can "easily" eliminate this problem, if we place the comma after__VA_ARGS__
conditionally, depending on the list being empty or not:That looked easy, but the
COMMA
macro is quite a heavy one; fortunately, the topic is already covered in a blog of Jens Gustedt (thanks, Jens). Basic trick is that function macros are not expanded if not followed by parentheses, for further explanations, have a look at Jens' blog... We just have to modify the macros a little to our needs (I'm going to use shorter names and less arguments for brevity).And now we are fine...
The complete code in one block: