Due to a fundamental issue in C pre-processor, elegant dispatching between function-like macro with a single and no-parameter is not possible without extensions. The upcoming C23 standard will support __VA_OPT__ which injects an extra token when the __VA_ARGS__ is non-empty. Usually it is a extra comma. This feature is already supported by some compilers including GCC and CLANG.
You can use NoArg trick as in the other answer but enhance it with __VA_OPT__ to support func() nicely.
#include <stdio.h>
#include <string.h>
void f1(void) { puts("F1");}
void f2(int n) { printf("F2 %d\n", n); }
typedef struct NoArg NoArg;
#define func(...) func_(__VA_ARGS__ __VA_OPT__(,) (NoArg*)0, ~ )(__VA_ARGS__)
#define func_(x, ...) \
  _Generic((x)        \
    , NoArg*: f1      \
    , int: f2         \
  )
int main(void) {
    func();
    func(5);
    return 0;
}
Works as expected. See godbolt.
The tricky part is the expansion of func macro to:
func_(__VA_ARGS__ __VA_OPT__(,) (NoArg*)0, ~ ) (__VA_ARGS__)
The tail of (__VA_ARGS__) keeps the original arguments to be used after the func_ is expanded to _Generic. The __VA_OPT__(,) adds a comma if and only if the parameter list is empty. Next, the (NoArg*)0 indicator is passed. It will be the first parameter is original parameter list was empty. Finally, the parameters are finished with dummy ~ to make sure that func_ macro is evaluated with at least two tokens letting use func_(x, ...) without issues with missing arguments.
EDIT
There is a way to do it in C11. Just use compound literal of an array type.
Use (int[]) { 0, __VA_ARGS__ }. Let empty list in func() expand to (int[]) { 0, } which is an array of type int[1] while let 5 in func(5) expands to (int[]) { 0, 5 } which is an array of type int[2]. Next take an address of such array to avoid "array decay" in _Generic. Dispatch a proper function from the type of an array pointer.
#include <stdio.h>
#include <string.h>
void f1(void) { puts("F1");}
void f2(int n) { printf("F2 %d\n", n); }
#define func(...) func_((&(int[]){ 0, __VA_ARGS__})) (__VA_ARGS__)
#define func_(x)    \
  _Generic((x)      \
    , int(*)[1]: f1 \
    , int(*)[2]: f2 \
  )
int main(void) {
    func(); // This will call f1
    func(5);     // This will call f2 with argument of 5
    return 0;
}
It compiles in a pedantic mode with no warning and it produces the expected output. See godbolt. The main disadvantage it that it can work only for integer parameters.
EDIT
As pointed by a comment from Lundin, there is even a simpler version that works for functions with any type.
#define func(...) \
  _Generic (& # __VA_ARGS__  \
    , char(*)[1]: f1         \
    , default: f2            \
  )(__VA_ARGS__)
The trick is stringification of parameter list. The empty one will be transformed to "". The extra spaces are removed as pointed in 6.10.3.2p2:
... White space before the first preprocessing token and after the last preprocessing token composing the argument is deleted. ...
The interesting thing about string literal is that they are technically L-values so one can take their address! It allows to dispatch expression from the type of the array pointer which is char(*)[1] for &"".