Есть ли эквивалент в C для шаблонов C ++? - PullRequest
14 голосов
/ 20 мая 2010

В коде, который я пишу, мне нужны функции foo(int, char*) и foo(int, int).

Если бы я кодировал это на C ++, я бы использовал шаблоны. Есть ли эквивалент для C? Или я должен использовать пустые указатели? Как?

Ответы [ 7 ]

28 голосов
/ 20 мая 2010

Я думаю, что ближе всего к C шаблонам можно найти некрасивый макрос-код. Например, чтобы определить простую функцию, которая дважды возвращает свой аргумент:

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

MAKE_DOUBLER(int)
MAKE_DOUBLER(float)

Обратите внимание, что, поскольку в C нет перегрузки функций, вы должны выполнять трюки с именем функции (в приведенном выше примере указаны и doubler_int, и doubler_float, и вам придется вызывать их так).

printf("%d\n", doubler_int(5));
printf("%f\n", doubler_float(12.3));
15 голосов
/ 20 мая 2010

Вы не можете этого сделать.
В C нет перегрузок, одна функция, одно имя, вам нужно использовать тип, который поддерживает все ваши потребности, например (недействительно *)

Либо так, либо делай foo_int(int,int) и foo_char(int, char*)

11 голосов
/ 24 мая 2016

Да, есть.Вы можете использовать типовое выражение в 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*.
6 голосов
/ 20 мая 2010

Другие обсуждали внутреннее ограничение c в отношении перегрузки. Однако обратите внимание, что если вы можете определить, какой случай необходим, вы можете использовать varargs:

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

Если вы не можете вывести это, вы можете передать дополнительный аргумент:

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

где spec сообщает функции, что ожидать в последующих аргументах. Как семейства функций printf и scanf. На самом деле, вам может быть удобно повторно использовать соглашения printf / scanf для указания типа, тем самым избавляя пользователей от необходимости использовать другой мини-язык.

3 голосов
/ 11 января 2018

Шаблоны могут быть реализованы с использованием заголовков шаблонов.

Пусть foo.h вот так:

#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

Чтобы использовать его, вы можете сделать:

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

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

Теперь у вас есть pchar_foo() и int_foo(), которые вы можете использовать.

Преимущества этого состоят в том, что если возникает проблема со сборкой, вы получаете номер строки в заголовке шаблона, а не компилятор, который просто говорит, что макрос неправильный, и завершение кода также работает в некоторых IDE.

Макросы PREFIX, CCAT и FN очень распространены, поэтому я выделил их определение в отдельный заголовок, а их определение - в другой.

Я реализовал части STL, используя этот шаблон для забавы, и использую его в некоторых своих проектах на C.

3 голосов
/ 02 января 2017

Вместо void * вы также можете использовать объединение для хранения данных любого типа:

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);
}

Конечно, вы должны создавать константы для значений типа.

0 голосов
/ 28 марта 2019

Вы можете использовать _Generic от GCC. (Хотя это НЕ переносимо на другие компиляторы) http://www.robertgamble.net/2012/01/c11-generic-selections.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...