Здравствуйте!
У меня есть два вопроса, которые меня мучают, и может быть вы
сможете помочь мне разрешить их.
1. Есть две функции. Они одинаковые — отличаются только типом
передаваемого аргумента vector<int> или vector<string>.
С помощью перегрузки функций я делаю так чтобы при вызове функции
выполнялась та в которой этот тип аргумента. Но приходится писать
обе функции — каждую cо своим типом аргумента (больше они ничем не
отличаются кроме типа аргумента). А если три типа? Тогда три функции.
Все работает. Но ведь эти функции отличаются только типом аргумента.
Как объединить их в одну? В этом весь вопрос. А то смотреть на такой
код не очень приятно.
2. Есть функция с изменяемым количеством аргументов.
Этот вопрос много раз обсуждался. Я читал. Мой вопрос в другом.
Если использовать va_list (а я его и использую), то приходится
вместе с аргументами передавать и их количество.
Т.е. например так: ( int n, ... )
А хотелось бы не передавать количество аргументов. А как то его
вычислять внутри функции или применить какой то другой подход.
Чтобы в итоге получилось ( ... ). Без int n.
Здравствуйте, <Аноним>, Вы писали:
А>Все работает. Но ведь эти функции отличаются только типом аргумента. А>Как объединить их в одну? В этом весь вопрос. А то смотреть на такой А>код не очень приятно.
Если ты используешь в этой функции только вектор с разными типами в нем, то почему бы не сделать эту функцию шаблонной?
Здравствуйте, Аноним, Вы писали:
А>1. Есть две функции. Они одинаковые — отличаются только типом передаваемого аргумента vector<int> или vector<string>. <...> функции отличаются только типом аргумента.
Как вариант, можно реализовать шаблонную функцию:
template<class T> f(T& v)
{
// do something with v
}
при вызове фактический тип параметра вычисляется компилятором:
vector<int> v1;
f(v1);
vector<string> v2;
f(v2)
Удалено избыточное цитирование. -- ПК.
Чтобы хорошо работать, надо получать от этого удовольствие! (c) Michael Schumacher
Здравствуйте, <Аноним>, Вы писали:
А>2. Есть функция с изменяемым количеством аргументов. А>Этот вопрос много раз обсуждался. Я читал. Мой вопрос в другом. А>Если использовать va_list (а я его и использую), то приходится А>вместе с аргументами передавать и их количество. А>Т.е. например так: ( int n, ... ) А>А хотелось бы не передавать количество аргументов. А как то его А>вычислять внутри функции или применить какой то другой подход. А>Чтобы в итоге получилось ( ... ). Без int n.
Формируй массив параметров и передавай.
Можно (см. примечание) делать это в выражении, перегрузив какой-либо бинарный оператор (например <<)
Здравствуйте, Кодт, Вы писали:
К>Примечание. К>VC разрешает создание временных объектов ( vint() ) неконстантных. К>Вообще это запрещено стандартом и даже пахнет undefined behaviour.
Нельзя ли привести соответствующий пункт Стандарта?
... << RSDN@Home 1.0 beta 6a >>
Re[2]: Перегрузка и передача аргументов в функцию
От:
Аноним
Дата:
23.04.03 12:34
Оценка:
Еще один вопрос-проблема.
va_arg не понимает string.
Т.е. если написать va_arg(marker, T) и если T string — программа вылетает.
А если написать va_arg(marker, char *) и если T string то все работает.
Т.е. без шаблона мы используем va_arg(marker, char *) и все работает.
А с шаблоном вынуждены писать va_arg(marker, T) и программа вылетает.
Если тип string. Если допустим int то конечно все работает.
Как это все обхитрить?
Здравствуйте, Михаил Можаев, Вы писали:
К>>VC разрешает создание временных объектов ( vint() ) неконстантных. К>>Вообще это запрещено стандартом и даже пахнет undefined behaviour.
ММ>Нельзя ли привести соответствующий пункт Стандарта?
Навскидку не скажу. Но это неоднократно обсуждалось.
Здравствуйте, Аноним, Вы писали:
А>Как это все обхитрить?
А>Т.е. невозможно? А может можно как то stdarg переписать. А>Есть у кого-нибудь идеи? Неужели облом?
В журнале программист, который, к сожалению, приказал долго жить, не была напечатана моя статья "Функции, указатели, ссылки (часть 3)", в которой я как раз довольно детально этот вопрос рассматриваю. Про string там не написано (контейнеры и функции с переменным числом параметров — тема отдельной статьи), но реально работающие программки с переменным числом указателей (и даже разнотипных) там есть. Возможно Вам это поможет решить Вашу проблему.
Сообщите адрес — пришлю мылом. Есть идея послать это в RSDN, да просто руки не доходят все по их требованиям форматировать.
А вообще я не вижу нужды использовать эти функции сейчас, поскольку контейнеры — динамические. Проще один контейнер передавать, чем изгаляться с переменным числом параметров.
Однако я не вижу это тема
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Кодт, Вы писали:
К>когда именно (*1* .. *4*) разрушить временный объект t0 — дело хозяйское.
А как же
C++ Standard, 12.2/2
Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.
f( container() << e1 << e2 << e3 )
Разве это — не full-expression? Вернее, это может быть частью full-expression, но тогда время жизни временного объекта еще больше.
К>Ограничение на неконстантность временных объектов в выражениях, имхо, предназначено для ловли таких логических ошибок.
Все же очень хотелось бы увидеть пункт Стандарта. Я пока не нашел...
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Михаил Можаев, Вы писали:
<>
К>Прошу у всех прощения. Погнал насчет undefined.
К>Но дежавю меня не покидает (в отношении неконстантности). Тем более, что Comeau С++ на это счет категорично выступил.
Насколько я помню, в Стандарте говорится только о том, что на временный объект можно завести только константную ссылку, но что сам временный объект внутри выражения должен быть константным — такого не припоминаю.
Здравствуйте, jazzer, Вы писали:
J>Насколько я помню, в Стандарте говорится только о том, что на временный объект можно завести только константную ссылку, но что сам временный объект внутри выражения должен быть константным — такого не припоминаю.
А номер пункта не помнишь?
Теперь к нашим барабанам.
container& operator << (container& c, element e) { ..... }
является функцией (только в инфиксной записи). Вот он-то и не может завести неконстантную ссылку.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[8]: Перегрузка и передача аргументов в функцию
От:
Аноним
Дата:
23.04.03 16:48
Оценка:
2Кодт: Ты чего творишь Все теперь стандарт обсуждают — а мне кто будет отвечать
Про мои вопросы все и забыли
Если нежелательно, чтобы пользователь имел доступ к потрохам этой функции, ты в хедере пишешь сигнатуры( fn(vector<int>), fn(vector<char>) и т.п.), а в компилируемом файле — из каждой сигнатуры функции просто вызываешь шаблонную функцию-реализацию ( template<class T>fn_imp(T) )
2. Как передавать переменное количество параметров, не пользуясь троеточием.
Для этого — есть контейнеры.
Чтобы объехать ограничение на неконстантные ссылки, используй мой класс Params
(правильный код выкладываю в форум "Исходники": http://www.rsdn.ru/forum/?mid=250651
3. Как передавать сложные объекты через троеточие.
Лучше вообще это не делать. Слишком небезопасный код получается.
Копия объекта кладется на стек.
Макрос va_arg(ptr, type) приводит ptr к (type*) и разыменовывает, а также сдвигает ptr на размер type (выравненный до размера int).
Ты должен твердо знать, что на стеке — данные именно этого типа. Иначе будет бубум.
void fn(int n, ...)
{
va_list va; va_start(va, n);
for(;n>0;--n)
cout << va_arg(va,string) << endl;
}
int main()
{
fn(2, string("hello"), string("world")); // можно
fn(2, "hello", "world"); // абзац!
}
В некоторых библиотеках идут на ухищрения.
Например, MFC: CString содержит только указатель на TCHAR*, и имеет размер 4. Поэтому нет разницы между параметром типа LPCTSTR и параметром типа CString (однако внутри функции нельзя писать va_arg(ptr, CString), так как там может быть простой TCHAR*, а CString по этому указателю не только строку держит...
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[10]: Перегрузка и передача аргументов в функцию
От:
Аноним
Дата:
24.04.03 06:40
Оценка:
Здравствуйте, Кодт, Вы писали:
К>2. Как передавать переменное количество параметров, не пользуясь троеточием.
К>Для этого — есть контейнеры.
Тут вообще-то все зависит от конкретной ситуации, от предназначения функций.
Для того, чтобы переписать printf для Си++, контейнеры не понадобились.