Перегрузка и передача аргументов в функцию
От: Аноним  
Дата: 23.04.03 10:35
Оценка:
Здравствуйте!
У меня есть два вопроса, которые меня мучают, и может быть вы
сможете помочь мне разрешить их.

1. Есть две функции. Они одинаковые — отличаются только типом
передаваемого аргумента vector<int> или vector<string>.
С помощью перегрузки функций я делаю так чтобы при вызове функции
выполнялась та в которой этот тип аргумента. Но приходится писать
обе функции — каждую cо своим типом аргумента (больше они ничем не
отличаются кроме типа аргумента). А если три типа? Тогда три функции.
Все работает. Но ведь эти функции отличаются только типом аргумента.
Как объединить их в одну? В этом весь вопрос. А то смотреть на такой
код не очень приятно.

2. Есть функция с изменяемым количеством аргументов.
Этот вопрос много раз обсуждался. Я читал. Мой вопрос в другом.
Если использовать va_list (а я его и использую), то приходится
вместе с аргументами передавать и их количество.
Т.е. например так: ( int n, ... )
А хотелось бы не передавать количество аргументов. А как то его
вычислять внутри функции или применить какой то другой подход.
Чтобы в итоге получилось ( ... ). Без int n.

Спасибо!
Re: Перегрузка и передача аргументов в функцию
От: Дмитрий Наумов  
Дата: 23.04.03 10:46
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Все работает. Но ведь эти функции отличаются только типом аргумента.

А>Как объединить их в одну? В этом весь вопрос. А то смотреть на такой
А>код не очень приятно.

Если ты используешь в этой функции только вектор с разными типами в нем, то почему бы не сделать эту функцию шаблонной?
... << RSDN@Home 1.0 beta 6a >>

Удалено избыточное цитирование. -- ПК.
Re: Перегрузка и передача аргументов в функцию
От: AlexanderK Россия  
Дата: 23.04.03 10:47
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>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

Re[2]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 11:09
Оценка: +1
Здравствуйте, AlexanderK, Вы писали:

AK>Здравствуйте, Аноним, Вы писали:


(на будущее: пожалуйста удаляйте лишние цитаты)

AK>Как вариант, можно реализовать шаблонную функцию:


AK>template<class T> f(T& v)
AK>{
AK>    // do something with v
AK>}


Другая форма записи (если все функции имеют дело именно с std::vector, а не любым контейнером):
template<class T>
f(std::vector<T>& v)
{ ..... }
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 11:59
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>2. Есть функция с изменяемым количеством аргументов.

А>Этот вопрос много раз обсуждался. Я читал. Мой вопрос в другом.
А>Если использовать va_list (а я его и использую), то приходится
А>вместе с аргументами передавать и их количество.
А>Т.е. например так: ( int n, ... )
А>А хотелось бы не передавать количество аргументов. А как то его
А>вычислять внутри функции или применить какой то другой подход.
А>Чтобы в итоге получилось ( ... ). Без int n.

Формируй массив параметров и передавай.

Можно (см. примечание) делать это в выражении, перегрузив какой-либо бинарный оператор (например <<)
template<class T, class E>
inline std::vector<T>& operator << (std::vector<T>& v, const E& e)
{
  v.push_back(e);
  return v;
}

typedef std::vector<int> vint;
void f(int x, const vint& y, int z)
{
  ...
  y.size();
  ...
  y[i];
  ...
}

int main()
{
  ...
  f(123, vint() << 1 << 2 << 3, 456);
  ...
}

Примечание.
VC разрешает создание временных объектов ( vint() ) неконстантных.
Вообще это запрещено стандартом и даже пахнет undefined behaviour.

Для более суровых компиляторов можно повыделываться.
Например, оператор << создает и возвращает копию контейнера.
template<class C>
class Params
{
  // типовое решение: умный указатель с подсчетом ссылок
private:
  C* cont;
  int* ref;
public:
  Params() : cont(new C), ref(new int(1)) {}
  Params(const Params& p) : cont(p.cont), ref(p.ref) { ++p.ref; }
  ~Params() { if(--(*ref) == 0) { delete cont; delete ref; } }

  // хотя сам объект константный, контейнер можно менять
  C& data() const { return cont; }
};

template<class C, class E>
Params<C> operator << (const Params<C>& p, const E& e)
{
  p.data().push_back(e);
  return p;
}
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[2]: Перегрузка и передача аргументов в функцию
От: Михаил Можаев Россия www.mozhay.chat.ru
Дата: 23.04.03 12:25
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Примечание.

К>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 то конечно все работает.
Как это все обхитрить?
Re[3]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 12:53
Оценка:
Здравствуйте, Михаил Можаев, Вы писали:

К>>VC разрешает создание временных объектов ( vint() ) неконстантных.

К>>Вообще это запрещено стандартом и даже пахнет undefined behaviour.

ММ>Нельзя ли привести соответствующий пункт Стандарта?


Навскидку не скажу. Но это неоднократно обсуждалось.

Почему здесь возможен undefined behaviour:

распишем выражение
f( container() << e1 << e2 << e3 )
построчно.
container t0();
container& t1 = t0 << e1;
/*1*/
container& t2 = t1 << e2;
/*2*/
container& t3 = t2 << e3;
/*3*/
f(t3);
/*4*/

когда именно (*1* .. *4*) разрушить временный объект t0 — дело хозяйское.

Ограничение на неконстантность временных объектов в выражениях, имхо, предназначено для ловли таких логических ошибок.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[3]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 12:53
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Как это все обхитрить?


Вообще не передавать в (...) составные не-POD данные (объекты, структуры с нетривиальными конструкторами).
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[4]: Перегрузка и передача аргументов в функцию
От: Аноним  
Дата: 23.04.03 12:58
Оценка:
А>Как это все обхитрить?

К>Вообще не передавать в (...) составные не-POD данные (объекты, структуры с нетривиальными конструкторами).


Т.е. невозможно? А может можно как то stdarg переписать.
Есть у кого-нибудь идеи? Неужели облом?
Re[5]: Перегрузка и передача аргументов в функцию
От: LaptevVV Россия  
Дата: 23.04.03 13:12
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как это все обхитрить?


А>Т.е. невозможно? А может можно как то stdarg переписать.

А>Есть у кого-нибудь идеи? Неужели облом?

В журнале программист, который, к сожалению, приказал долго жить, не была напечатана моя статья "Функции, указатели, ссылки (часть 3)", в которой я как раз довольно детально этот вопрос рассматриваю. Про string там не написано (контейнеры и функции с переменным числом параметров — тема отдельной статьи), но реально работающие программки с переменным числом указателей (и даже разнотипных) там есть. Возможно Вам это поможет решить Вашу проблему.

Сообщите адрес — пришлю мылом. Есть идея послать это в RSDN, да просто руки не доходят все по их требованиям форматировать.

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



Однако я не вижу это тема
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Перегрузка и передача аргументов в функцию
От: LaptevVV Россия  
Дата: 23.04.03 13:16
Оценка:
Здравствуйте, Аноним,

А>Т.е. невозможно? А может можно как то stdarg переписать.

А>Есть у кого-нибудь идеи? Неужели облом?

Вдогонку — забыл свой адрес прописать.
Laptev@astu.astranet.ru
Лаптев Валерий
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[4]: Перегрузка и передача аргументов в функцию
От: Аноним  
Дата: 23.04.03 13:20
Оценка:
Здравствуйте, Кодт, Вы писали:

К>распишем выражение

К>f( container() << e1 << e2 << e3 )
К>построчно.
К>
К>container t0();
К>container& t1 = t0 << e1;
К>/*1*/
К>container& t2 = t1 << e2;
К>/*2*/
К>container& t3 = t2 << e3;
К>/*3*/
К>f(t3);
К>/*4*/
К>

К>когда именно (*1* .. *4*) разрушить временный объект t0 — дело хозяйское.

Не хозяйское. Только в конце вычисления полного выражения.
Re[4]: Перегрузка и передача аргументов в функцию
От: Михаил Можаев Россия www.mozhay.chat.ru
Дата: 23.04.03 13:35
Оценка: 14 (1)
Здравствуйте, Кодт, Вы писали:

К>когда именно (*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, но тогда время жизни временного объекта еще больше.

К>Ограничение на неконстантность временных объектов в выражениях, имхо, предназначено для ловли таких логических ошибок.


Все же очень хотелось бы увидеть пункт Стандарта. Я пока не нашел...
... << RSDN@Home 1.0 beta 6a >>
Re[5]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 13:39
Оценка:
Здравствуйте, Михаил Можаев, Вы писали:

<>

Прошу у всех прощения. Погнал насчет undefined.

Но дежавю меня не покидает (в отношении неконстантности). Тем более, что Comeau С++ на это счет категорично выступил.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[6]: Перегрузка и передача аргументов в функцию
От: jazzer Россия Skype: enerjazzer
Дата: 23.04.03 15:04
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Михаил Можаев, Вы писали:


<>

К>Прошу у всех прощения. Погнал насчет undefined.


К>Но дежавю меня не покидает (в отношении неконстантности). Тем более, что Comeau С++ на это счет категорично выступил.


Насколько я помню, в Стандарте говорится только о том, что на временный объект можно завести только константную ссылку, но что сам временный объект внутри выражения должен быть константным — такого не припоминаю.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 15:51
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Насколько я помню, в Стандарте говорится только о том, что на временный объект можно завести только константную ссылку, но что сам временный объект внутри выражения должен быть константным — такого не припоминаю.


А номер пункта не помнишь?

Теперь к нашим барабанам.
container& operator << (container& c, element e) { ..... }

является функцией (только в инфиксной записи). Вот он-то и не может завести неконстантную ссылку.
... << RSDN@Home 1.0 beta 6a >>
Перекуём баги на фичи!
Re[8]: Перегрузка и передача аргументов в функцию
От: Аноним  
Дата: 23.04.03 16:48
Оценка: :)
2Кодт: Ты чего творишь Все теперь стандарт обсуждают — а мне кто будет отвечать
Про мои вопросы все и забыли
Re[9]: Перегрузка и передача аргументов в функцию
От: Кодт Россия  
Дата: 23.04.03 17:45
Оценка: 2 (1)
Здравствуйте, <Аноним>, Вы писали:

А>Про мои вопросы все и забыли


Итак, по пунктам.

1. Как объединить несколько одинаковых функций, различающихся только аргументом.

Для этого есть шаблоны (template).
template< class Container >
void fn( ..... Container cont ..... ) { ..... }

Если нежелательно, чтобы пользователь имел доступ к потрохам этой функции, ты в хедере пишешь сигнатуры( fn(vector<int>), fn(vector<char>) и т.п.), а в компилируемом файле — из каждой сигнатуры функции просто вызываешь шаблонную функцию-реализацию ( template<class T>fn_imp(T) )

2. Как передавать переменное количество параметров, не пользуясь троеточием.

Для этого — есть контейнеры.
Чтобы объехать ограничение на неконстантные ссылки, используй мой класс Params
(правильный код выкладываю в форум "Исходники": http://www.rsdn.ru/forum/?mid=250651
Автор: Кодт
Дата: 23.04.03
)

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 для Си++, контейнеры не понадобились.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.