Есть ли способ добиться перегрузки функции в C? Я смотрю на простые функции, которые будут перегружены, как
foo (int a)
foo (char b)
foo (float c , int d)
Я думаю, что нет прямого пути; Я ищу обходные пути, если таковые существуют.
c
overloading
FL4SOF
источник
источник
Ответы:
Есть несколько возможностей:
источник
Да!
Со времени, когда этот вопрос был задан, стандарт C (без расширений) фактически получил поддержку перегрузки функций (не операторов) благодаря добавлению
_Generic
ключевого слова в C11. (поддерживается в GCC начиная с версии 4.9)(Перегрузка на самом деле не является «встроенной» в способе, показанном в вопросе, но реализовать что-то, что так работает, очень просто.)
_Generic
является оператором времени компиляции в том же семействе, чтоsizeof
и_Alignof
. Это описано в стандартном разделе 6.5.1.1. Он принимает два основных параметра: выражение (которое не будет оцениваться во время выполнения) и список ассоциаций типа / выражения, который немного похож наswitch
блок._Generic
получает общий тип выражения, а затем переключается на него, чтобы выбрать выражение конечного результата в списке для его типа:Вышеупомянутое выражение оценивается
2
как тип управляющего выраженияint
, поэтому вint
качестве значения выбирается выражение, связанное с . Ничего из этого не остается во время выполнения. (Предложениеdefault
является необязательным: если вы укажете его, а тип не будет совпадать, это приведет к ошибке компиляции.)Это полезно для перегрузки функций, так как она может быть вставлена препроцессором C и выбирать выражение результата на основе типа аргументов, передаваемых управляющему макросу. Итак (пример из стандарта C):
Этот макрос реализует перегруженную
cbrt
операцию, отправляя тип аргумента макросу, выбирая соответствующую функцию реализации, а затем передавая исходный аргумент макроса этой функции.Итак, чтобы реализовать ваш оригинальный пример, мы могли бы сделать это:
В этом случае мы могли бы использовать
default:
ассоциацию для третьего случая, но это не демонстрирует, как распространить принцип на несколько аргументов. Конечным результатом является то, что вы можете использоватьfoo(...)
в своем коде, не беспокоясь (много [1]) о типе его аргументов.Для более сложных ситуаций, например функций, перегружающих большее количество аргументов или меняющихся чисел, вы можете использовать служебные макросы для автоматической генерации статических структур диспетчеризации:
( реализация здесь ) Таким образом, прилагая некоторые усилия, вы можете уменьшить количество стандартного шаблона, чтобы он выглядел почти как язык с встроенной поддержкой перегрузки.
Кроме того, уже было возможно перегружать количество аргументов (не тип) в C99.
[1] обратите внимание, что способ, которым C оценивает типы, может вас сбить с толку. Это выберет, например,
foo_int
если вы попытаетесь передать ему символьный литерал, и вам нужно немного повозиться, если вы хотите, чтобы ваши перегрузки поддерживали строковые литералы. Все же в целом довольно круто, хотя.источник
Как уже говорилось, перегрузка в том смысле, который вы имеете в виду, не поддерживается C. Обычной идиомой для решения проблемы является заставить функцию принимать теговое объединение . Это реализуется
struct
параметром, гдеstruct
сам состоит из некоторого типа индикатора типа, такого какenum
, и aunion
из различных типов значений. Пример:источник
whatever
S на отдельные функции (set_int
,set_float
и т.д.). Затем «тегирование с типом» становится «добавить имя типа к имени функции». Версия в этом ответе включает в себя больше печатания, больше затрат времени выполнения, больше шансов на ошибки, которые не будут обнаружены во время компиляции ... Я не вижу никакого преимущества в таких действиях! 16 голосов ?!Вот самый ясный и краткий пример, который я нашел, демонстрирующий перегрузку функций в C:
https://gist.github.com/barosl/e0af4a92b2b8cabd05a7
источник
Если ваш компилятор - gcc, и вы не возражаете делать обновления рук каждый раз, когда добавляете новую перегрузку, вы можете сделать некоторую макрокоманду и получить желаемый результат с точки зрения вызывающих абонентов, это не так приятно писать ... но это возможно
посмотрите на __builtin_types_compatible_p, затем используйте его для определения макроса, который делает что-то вроде
но да противно, просто не
РЕДАКТИРОВАТЬ: C1X будет получать поддержку универсальных выражений типа они выглядят так:
источник
Да вроде.
Вот вам пример:
Он выведет 0 и привет .. из printA и printB.
источник
Следующий подход аналогичен a2800276 , но с добавлением некоторой макро-магии C99:
источник
Это может не помочь вообще, но если вы используете clang, вы можете использовать атрибут overloadable - это работает даже при компиляции как C
http://clang.llvm.org/docs/AttributeReference.html#overloadable
заголовок
Реализация
источник
В том смысле, что вы имеете в виду - нет, вы не можете.
Вы можете объявить
va_arg
функцию какvoid my_func(char* format, ...);
, но вам нужно передать некоторую информацию о количестве переменных и их типах в первом аргументе - как это
printf()
делает.источник
Обычно бородавка для обозначения типа добавляется или добавляется к имени. С некоторыми макросами можно обойтись, но это скорее зависит от того, что вы пытаетесь сделать. Там нет полиморфизма в C, только принуждение.
Простые общие операции можно выполнить с помощью макросов:
Если ваш компилятор поддерживает typeof , в макрос можно добавить более сложные операции. Затем вы можете использовать символ foo (x) для поддержки одной и той же операции различными типами, но вы не можете изменять поведение между разными перегрузками. Если вам нужны реальные функции, а не макросы, возможно, вы сможете вставить тип в имя и использовать вторую вставку для доступа к нему (я не пробовал).
источник
Ответ Леушенко действительно клевый - исключительно:
foo
пример не компилируется с GCC, который терпит неудачуfoo(7)
, спотыкаясь оFIRST
макросе и фактическом вызове функции ((_1, __VA_ARGS__)
оставаясь с лишней запятой. Кроме того, у нас проблемы, если мы хотим обеспечить дополнительные перегрузки , такие какfoo(double)
.Поэтому я решил развить ответ немного дальше, в том числе разрешить пустую перегрузку (
foo(void)
- которая вызвала некоторые проблемы ...).Идея теперь такова: определите более одного универсального в разных макросах и позвольте выбрать правильный в соответствии с количеством аргументов!
Количество аргументов довольно просто, исходя из этого ответа :
Это хорошо, мы разрешаем либо
SELECT_1
илиSELECT_2
(или больше аргументов, если вы хотите / нуждаетесь в них), поэтому нам просто нужны соответствующие определения:Хорошо, я уже добавил перегрузку void - однако, она на самом деле не охватывается стандартом C, который не допускает пустых переменных аргументов, т.е. мы тогда полагаемся на расширения компилятора !
Сначала пустой вызов макроса (
foo()
) по-прежнему создает токен, но пустой. Таким образом, счетный макрос фактически возвращает 1 вместо 0 даже при пустом вызове макроса. Мы можем «легко» устранить эту проблему, если поставить__VA_ARGS__
условную запятую после , в зависимости от того, пустой список или нет:Это выглядело легко, но
COMMA
макрос довольно тяжелый; К счастью, эта тема уже освещена в блоге Jens Gustedt (спасибо, Jens). Основная хитрость заключается в том, что макросы функций не раскрываются, если за ними не следуют круглые скобки, для дальнейших объяснений загляните в блог Йенса ... Нам просто нужно немного изменить макросы в соответствии с нашими потребностями (я собираюсь использовать более короткие имена и меньше аргументов для краткости).И теперь у нас все хорошо ...
Полный код в одном блоке:
источник
Разве вы не можете просто использовать C ++ и не использовать все другие функции C ++, кроме этой?
Если все еще нет строгого C, то я бы порекомендовал функции с переменным числом .
источник
Попробуйте объявить эти функции так, как
extern "C++"
если бы ваш компилятор это поддерживал, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspxисточник
Я надеюсь, что приведенный ниже код поможет вам понять перегрузку функции
источник