Всем привет. Хочу написать функцию которой передается количество аргументов и аргументы возможно разного типа. Например, чтобы можно было вызвать функцию примерно так print(3, 1, 1.9, "abc"). Погуглил немного ничего для определения типа не нашел может кто знает как это сделать? Если для параметров тип заранее известен то можно так:
// ...
#include <cstdarg>
// ...
inline void print(int n, ...)
{
va_list params;
va_start(params, n);
if (n == 1)
{
int x = va_arg(params, int);
cerr << "int " << x << endl;
}
else
{
char* x = va_arg(params, char*);
cerr << "string " << x << endl;
}
va_end(params);
}
// ...
UPD: Всем спасибо за ответы. Результат видимо такой: в обычном стандарте С++ нормально это не делается, а в С++11 есть свои фишки о которых написал cmd
Забавно, минут 10 назад это обсуждали.
Такие функции работают методом "положили все на стек, а дальше разбирайся сам". Насколько я понимаю никакой информации про тип при этом не сохраняется. В частности scanf/printf поэтому берут его из format_string.
Какая школота заминусовала пост? Паша абсолютно прав.
Это вроде бы не возможно. Собственно, потому что мы ничего не знаем о полученных аргументах, мы и должны передавать сперва инфрмацию: кол-во аргументов, формат для printf'a или т.п.
Буквально вчера почти из-за этого бросил попытки написать проект на С++ и сел изучать Java. Присоединяюсь к ораторам выше — на С++ это сделать невозможно.
Можно сделать на variadic templates которые появились в C++11. Пример c printf и variadic templates
Если лишнее убрать, то получится: http://ideone.com/s1LlH
UPD: вариант с выводом некоторых типов: http://ideone.com/9nBfZ.
Вот это круто
type_info::name()
заработал бы, если его пропустить черезabi:__cxa_demangle()
.На самом деле можно обойти тот факт, что аргументы могут быть разного типа, заменить их на union. Тогда понятно, что будет лежать в стеке. Например вот так . Печать правда не будет выглядить так хорошо, но ведь все равно так можно делать при желании.
P.S. Кто-то знает, почему оно на ideone.com выдаёт SIGILL? На моём компьютере все работает прекрасно.
Можно сделать замечание, что объекты в стеке не обязательно расположены так, что
(&n)+1
илиi++
будет работать. То есть, их всё равно нужно доставать черезva_arg
. Однако это не исправляетSIGILL
:-)На Stack Overflow ответили, что эта программа на самом деле вызывает undefined behavior.
Ссылки на стандарт C++ 2003:
...
, должен быть POD (Plain Old Data).union multytype
таковые имеет → FAIL.Странно... Ну раз так по стандарту делать не надо, то ладно. Буду знать.
Только сейчас подумал, а зачем нужен конструктор, когда можно все сделать C-образным.
http://ideone.com/bSzz7
Так оно работает :)
Развивая идею, можно ещё и избавиться от
mt()
в вызовеprint
и вообще от varargs: http://ideone.com/isFEoПравда, требует
__VA_ARGS__
, которого нет в C++98/03.