1

This is my code:

 #include <stdio.h>
 #include <tgmath.h>

 double complex execmathfunc(double complex val, double complex (*mathfunc)(double complex))
 {
     return mathfunc(val);
 }

 int main()
 {
     double complex val = -1;
     val = execmathfunc(val, sqrt); //if I put csqrt here it works
     printf("%.1f+%.1fi", creal(val), cimag(val));
     return 0;
 }

This code works if I use csqrt, and will output 0.0+1.0i as expected, but if I use regular sqrt (putting my hopes in the type-generic functions of tgmath.h), it outputs a garbage value for the real part and 0 for the imaginary part. Is there any way to get around that or do I need to stick with csqrt and all the other complex functions when passing them as arguments?

I believe the code behaves this way because the tgmath functions are implemented as functional macros and those only expand if the name is followed by ().

DarkAtom
  • 2,589
  • 1
  • 11
  • 27

3 Answers3

1

There is no such thing as type-generic function pointers in C.

However, you could have a struct of pointers for different relevant types, e.g.


typedef enum  { 
    USE_FLOAT = 0,
    USE_DOUBLE = 1, 
    // USE_LONG_DOUBLE = 2   // maybe you have this one as well
} complex_component_type_selector;

typedef struct {
    union {
        float complex (*float_)(float complex);
        double complex(*double_)(double complex);
    } function_ptr;
    complex_component_type_selector component_type;
} variant_function;

typedef union {
   union {
       float complex float_;
       double complex double_
   } datum;
   complex_component_type_selector component_type;
} variant_complex_datum;

and with that you can pass variant_complex_function along with a variant_complex_datum to sort-of-kind-of get what you wanted.

... Now, my suggestion is a bit crass and half-assed implementation of some variants. I'm sure there are libraries for C which are more sophisticated and comprehensive... oh yeah, here you go:

Variant datatype library for C

einpoklum
  • 118,144
  • 57
  • 340
  • 684
0

A _Complex double is not a double, and sqrt takes a double, while csqrt takes a _Complex double. I have not checked implementations, but I would say you are passing what is in fact a pointer to the sqrt function instead of a number.

mdp
  • 33
  • 8
  • 1
    I know, but I am `#include`ing `tgmath.h`, which should make the compiler choose the correct function from the type used, just like in C++ overloading. – DarkAtom Apr 07 '19 at 19:42
  • 1
    @MarkBenningfield Actually, that's what tgmath does. If I were to directly call sqrt from main with a _Complex argument, it would work. – DarkAtom Apr 07 '19 at 19:45
  • @DarkAtom: Exactly. But the use of a function pointer to redirect that call does not work, because the C compiler does not do type resolution that way. – Mark Benningfield Apr 07 '19 at 19:47
  • @MarkBenningfield, yes, and I am asking if there is a workaround. I am not sure if it is possible to overload execmathfunc itself using the _Generic keyword, because of the complexity of function pointer types. – DarkAtom Apr 07 '19 at 19:50
  • @DarkAtom: Not without a lot of tedious boilerplate, I don't think. And it would be rather brittle, IMO. – Mark Benningfield Apr 07 '19 at 19:53
0

I believe the code behaves this way because the tgmath functions are implemented as functional macros and those only expand if the name is followed by ().

Yes

Is there any way to get around that ... ?

No direct way around it.

Using <tgmath.h>, code cannot extract the function that would be called with an object of some type.

You could write your own function set using _Generic, yet I think you know that and are trying to avoid it.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256