Как я могу написать функцию, которая принимает переменное число аргументов? Это возможно, как?
c++
variadic-functions
nunos
источник
источник
Ответы:
Вы, вероятно, не должны, и вы, вероятно, можете делать то, что хотите, более безопасным и простым способом. Технически, чтобы использовать переменное число аргументов в C, вы включаете stdarg.h. Из этого вы получите
va_list
тип, а также три функции, которые работают с нимva_start()
,va_arg()
и , иva_end()
.Если вы спросите меня, это беспорядок. Выглядит плохо, небезопасно и полно технических деталей, которые не имеют ничего общего с тем, чего вы концептуально пытаетесь достичь. Вместо этого рассмотрите возможность использования перегрузки или наследования / полиморфизма, шаблона компоновщика (как в
operator<<()
потоках) или аргументов по умолчанию и т. Д. Все они безопаснее: компилятор узнает больше о том, что вы пытаетесь сделать, поэтому есть больше случаев, когда он может остановиться Вы, прежде чем оторвать ногу.источник
...
синтаксисом?printf()
, например, функция анализирует строковый аргумент для специальных токенов, чтобы выяснить, сколько дополнительных аргументов следует ожидать в списке переменных аргументов.<cstdarg>
в C ++ вместо<stdarg.h>
В C ++ 11 у вас есть две новые опции, как указано в справочной странице функций Variadic в разделе « Альтернативы» :
Ниже приведен пример, показывающий обе альтернативы ( смотрите вживую ):
Если вы используете
gcc
илиclang
мы можем использовать магическую переменную PRETTY_FUNCTION для отображения сигнатуры типа функции, которая может быть полезна для понимания происходящего. Например, используя:приведет к следующему int для функций с переменным числом в примере ( см. в прямом эфире ):
В Visual Studio вы можете использовать FUNCSIG .
Обновление до C ++ 11
До C ++ 11 альтернативой для std :: initializer_list был бы std :: vector или один из других стандартных контейнеров :
и альтернативой для шаблонов с переменными параметрами будут функции с переменными числами, хотя они не являются безопасными с точки зрения типов и, как правило, подвержены ошибкам и могут быть небезопасными для использования, но единственной другой потенциальной альтернативой будет использование аргументов по умолчанию , хотя это имеет ограниченное использование. Пример ниже представляет собой модифицированную версию примера кода в связанной ссылке:
Использование функций с переменным числом аргументов также имеет ограничения в аргументах, которые вы можете передать, что подробно описано в проекте стандарта C ++ в разделе «
5.2.2
Вызов функции», параграф 7 :источник
typename
противclass
использования выше преднамеренным? Если так, пожалуйста, объясните.initializer_list
рекурсив?Решение C ++ 17: полная безопасность типов + приятный синтаксис вызова
Поскольку введение шаблонов переменных в C ++ 11 и выражений сворачивания в C ++ 17, можно определить функцию-шаблон, которая на сайте вызывающей стороны может вызываться так, как если бы она была функцией Varidic, но с преимуществами для :
Вот пример для смешанных типов аргументов
И еще один с принудительным совпадением типов для всех аргументов:
Больше информации:
источник
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
иTail...
одинаковы », где « то же самое » означаетstd::conjunction<std::is_same<Head, Tail>...>
. Прочитайте это последнее определение как «Head
такое же, как всеTail...
».в C ++ 11 вы можете сделать:
инициализатор списка FTW!
источник
В C ++ 11 есть способ создания шаблонов переменных аргументов, который приводит к действительно элегантному и безопасному типу способу иметь функции переменных аргументов. Сам Бьярне приводит хороший пример printf с использованием шаблонов переменных аргументов в C ++ 11FAQ .
Лично я считаю это настолько элегантным, что даже не стал бы беспокоиться о функции с переменным аргументом в C ++, пока этот компилятор не будет поддерживать шаблоны переменных C ++ 11.
источник
,
оператор с выражениями свертывания). Иначе я так не думаю.В C ++ поддерживаются функции с переменным числом символов.
Однако большинство библиотек C ++ используют альтернативные идиомы, например, в то время как
'c' printf
функция принимает переменные аргументы,c++ cout
объект использует<<
перегрузку, которая затрагивает безопасность типов и ADT (возможно, за счет простоты реализации).источник
std::initializer_lists
... И это уже вносит огромную сложность в простую задачу.Помимо varargs или перегрузки, вы можете собирать свои аргументы в std :: vector или другие контейнеры (например, std :: map). Что-то вроде этого:
Таким образом, вы получите безопасность типов, и логический смысл этих переменных аргументов будет очевиден.
Конечно, у этого подхода могут быть проблемы с производительностью, но вам не следует беспокоиться о них, если вы не уверены, что не можете заплатить цену. Это своего рода "Pythonic" подход к C ++ ...
источник
Единственный способ - использование аргументов переменных в стиле C, как описано здесь . Обратите внимание, что это не рекомендуемая практика, так как она не безопасна и подвержена ошибкам.
источник
Не существует стандартного C ++ способа сделать это без использования varargs в стиле C (
...
).Конечно, есть аргументы по умолчанию, которые выглядят как переменное число аргументов в зависимости от контекста:
Все четыре вызова функций вызывают
myfunc
с различным количеством аргументов. Если ничего не указано, используются аргументы по умолчанию. Заметьте, однако, что вы можете опустить только конечные аргументы. Нет способа, например, опуститьi
и дать толькоj
.источник
Возможно, вы хотите перегрузку или параметры по умолчанию - определите ту же функцию с параметрами по умолчанию:
Это позволит вам вызывать метод одним из четырех разных вызовов:
... или вы можете искать соглашения о вызовах v_args из C.
источник
Если вы знаете диапазон количества аргументов, которые будут предоставлены, вы всегда можете использовать перегрузку некоторых функций, например
и так далее...
источник
Использование вариадических шаблонов, пример для воспроизведения,
console.log
как видно из JavaScript:Например, имя файла
js_console.h
:источник
Как уже говорили другие, С-стиль varargs. Но вы также можете сделать нечто подобное с параметрами по умолчанию.
источник
Теперь это возможно ... используя boost any и шаблоны. В этом случае тип аргументов может быть смешанным
источник
Объедините решения C и C ++ для семантически простого, производительного и наиболее динамичного варианта. Если вы облажались, попробуйте что-нибудь еще.
Пользователь пишет:
Семантически это выглядит и ощущается в точности как функция с n аргументами. Под капотом вы можете распаковать его так или иначе.
источник
Мы также могли бы использовать initializer_list, если все аргументы являются константными и имеют одинаковый тип
источник
Обычная версия
источник