开发者

Is there an equivalent in C for C++ templates?

In the code I am writing I need foo(int, char*) and foo(int, int) functions.

If I was coding this in C++ I would use templates. Is there any e开发者_如何学Cquivalent for C? Or should I use void pointers? How?


I think the closest you can get in C to templates is some ugly macro code. For example, to define a simple function that returns twice its argument:

#define MAKE_DOUBLER(T)  \
    T doubler_##T(T x) { \
        return 2 * x;    \
    }

MAKE_DOUBLER(int)
MAKE_DOUBLER(float)

Note that since C doesn't have function overloading, you have to play tricks with the name of the function (the above makes both doubler_int and doubler_float, and you'll have to call them that way).

printf("%d\n", doubler_int(5));
printf("%f\n", doubler_float(12.3));


Yes, there is. You can use type-generic expression in C11:

#include <stdio.h>

void foo_char_ptr(int a, char *b) {
  printf("Called int, char*.\n");
}

void foo_int(int a, int b) {
  printf("Called int, int.\n");
}

#define foo(a, b) _Generic((b), char*: foo_char_ptr, int: foo_int)(a, b)

int main() {
  foo(1, 1);
  foo(1, "foo");
}

// Output:
// Called int, int.
// Called int, char*.


You can't do that.
In C there are no overloads, one function, one name, you'll need to use a type that supports all your needs, e.g. (void *)

Either that or do a foo_int(int,int) and a foo_char(int, char*)


Templates can be realized using template headers.

Let foo.h like this:

#ifndef PREFIX
    #define PREFIX
#endif
#define CCAT2(x, y) x ## y
#define CCAT(x, y) CCAT2(x, y)
#define FN(x) CCAT(PREFIX, x)

#ifndef T
    #error Template argument missing.
#endif

void FN(foo)(int x, T t)
{
    // Whatever.
}


#undef T
#undef PREFIX
#undef CCAT2
#undef CCAT
#undef FN

To use it you can do:

#define T char*
#define PREFIX pchar_
#include "foo.h"

#define T int
#define PREFIX int_
#include "foo.h"

Now you have pchar_foo() and int_foo() which you can use.

The advantages of this is that if there is a build problem, you get line number in the template header instead of the compiler just saying the macro is wrong, and code completion works too in some IDEs.

The PREFIX, the CCAT and FN macros are very common so I extracted their definition into a separate header, and their undefinition to another one.

I implemented parts of the STL using this pattern for fun and use it in some of my C projects.


Others have discussed the intrinsic limitation of c with regard to overloading. Note, however, that if you can deduce which case is needed you can use varargs:

#include <stdarg.h>
foo(int, ...);

If you can't deduce it, you can pass an extra argument:

foo(int, char *spec, ...);

where spec tells the function what to expect in the subsequent arguments. Like the printf and scanf families of functions. In fact, you might find it convenient to reuse the printf/scanf conventions for specifying type, thus saving your users from having to lean another mini-language.


Instead of void* you can also use a union to hold any type of data you need:

typedef struct {
    int type;
    union {
        char* char_ptr;
        int int_val;
        // etc...
    };
} foo_data;

void foo(foo_data data)
{
    switch (data.type) {
        case 0:
            printf("%s\n", data.char_ptr);
            break;
        case 1:
            printf("%i\n", data.int_val);
            break;
    }
}

void main()
{
    foo_data data;

    data.type = 0; data.char_ptr = "hello";
    foo(data);
    data.type = 1; data.int_val  = 12;
    foo(data);
}

Of course, you should create constants for the type values.


You can use _Generic from GCC. (Although this is NOT portable to other compilers) http://www.robertgamble.net/2012/01/c11-generic-selections.html

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜