LINUX.ORG.RU

[C++] Переменное количество параметров в аргументах функции


0

0

Как сделать сабж? Во всех примерах, которые мне попадались, мухлюют: в качестве первого параметра передают общее количество параметров, либо последним передают "-1" либо «0».

Можно ли в функции с переменным количеством параметров определить общее их число без подобных хаков?


[C++] Переменное количество параметров в аргументах функции

нет

mannaz ()

[C++] Переменное количество параметров в аргументах функции

template<typename T1>
void Func(T1 *t1);

template<typename T1, typename T2>
void Func(T1 *t1,T2 *t2);

template<typename T1, typename T2, typename T3>
void Func(T1 *t1,T2 *t2,T3 *t3);

c++way

lester_dev ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Ещё можно посмотреть на printf, как он работает с переменным числом параметров. Посмотреть, и никогда так не делать :)

А вообще С++ и переменное число параметров - вещи плохо совместимые. Лучше всего вообще не писать такие функции, или писать в стиле printf. Например объекты нельзя передавать в эти самые функции. Если и другие ограничения, подробнее в стандарте.

Legioner ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Можно попробовать.

Агрументы функции передаются через стек (для вызова типа C и STD_CALL). Можно пройтись по стеку в поисках адреса возврата для предыдущей функции.

Или это тоже хак?

Liosha_Syrnikov ()

Re: [C++] Переменное количество параметров в аргументах функции

>>va_list - это для Си.

А что в C++?

классы же!
вашстрауструп

ЗЫ:
можно заюзать какой-нибудь контейнер.
или сделать по принципу манипуляторов ввода/вывода в потоки.

xydo ★★ ()

Re: [C++] Переменное количество параметров в аргументах функции

>Или это тоже хак?
хак, причем не только очень грязный, но и жутко вонючий!

возникают проблемы:
1) как определить, является ли число адресом?
2) как определить, является ли число адресом функции?
3) как определить, является ли число адресом вызванной функции, а не каким-нибудь коллбэком (хотя на ЦПП колбеки вроде не нужны особо)?
4) как определить, является ли число-не-адрес параметром функции или локальной переменной?

xydo ★★ ()

[C++] Переменное количество параметров в аргументах функции

можно заюзать какой-нибудь контейнер.

а в какой контейнер можно положить одновременно int, double, void *, и MyObject?

jtootf ★★★★★ ()

Re: [C++] Переменное количество параметров в аргументах функции

Попробую я ответить :-)

Контейнер QVariant (правда, насчет YourObject не уверен)

http://qt.nokia.com/doc/4.5/qvariant.html

P.S. Тут есть доля шутки, если что...

Liosha_Syrnikov ()

[C++] Переменное количество параметров в аргументах функции

>а в какой контейнер можно положить одновременно int, double, void *, и MyObject?

А что union нынче не кошерен? Только не надо в контейнер ложить MyObject лучше MyObject*. Делаем обычный массив из union и передаем. В большинстве случаев этого хватит. Без всяких мерзких stl::vector и ещё более мерзких шаблонов.

pathfinder ★★★★ ()

[C++] Переменное количество параметров в аргументах функции

А вообще по осторожнее надо в C/C++ c функциями с переменным числом параметров. Будет либо небезопасно, либо жутко тормозззно, либо недостаточно гибко. Чем-то прийдется пожертвовать.

pathfinder ★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> А что union нынче не кошерен?

а в какой контейнер можно положить одновременно int, double, void *, и MyObject?

а в какой контейнер можно положить одновременно


положить одновременно


одновременно</i>

LamerOk ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> одновременно</i>

очевидно имелся ввиду массив юнионов, хотя к каждому юниону надо еще и тип указывать, да и предложение использовать везде MyObject* - несерьезно

lester ★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Маловероятно. Судя по http://www.linux.org.ru/jump-message.jsp?msgid=4275052&cid=4277953 , кое-кто не очень внимательно читает сообщения, на которые отвечает.

LamerOk ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> одновременно</i>

[censored] всё разжевывать. LamerOk (ник как бы намекает) наверное будет удивлен, но массив из union может хранить любые элементы указанные в типе union. Для определения типа делаем либо структуру с union и идентификатором типа. Либо информацию о типе данных передаём как-то ещё, можно это сделать как в printf через строку.

pathfinder ★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Как я уже говорил универсального варианта не существует. Каждый способ решения этой задачи имеет свои серьезные недостатки.

pathfinder ★★★★ ()

[C++] Переменное количество параметров в аргументах функции

либо структуру с union и идентификатором типа. Либо информацию о типе данных передаём как-то ещё

иными словами, ты предлагаешь два костыля, ограниченно работающих с типами данных C++, и ещё удивлешься - чем же union не кошерен?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

либо небезопасно, либо жутко тормозззно, либо недостаточно гибко. Чем-то прийдется пожертвовать.

и как именно будет в случае использования вариадических шаблонов? небезопасно? тормозно? негибко?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Необходимость использования функций с переменным числом аргументов
в C++ говорит о проблемах с дизайном.

blackice ()

Re: [C++] Переменное количество параметров в аргументах функции

> и как именно будет в случае использования вариадических шаблонов? небезопасно? тормозно? негибко?

Учитывая, что без рекурсии обойти по порядку все параметры вариадического шаблона будет проблематично, можно сказать, что «негибко».

mannaz ()

[C++] Переменное количество параметров в аргументах функции

Учитывая, что без рекурсии обойти по порядку все параметры вариадического шаблона будет проблематично, можно сказать, что «негибко».

а как рекурсия ухудшает эту самую гибкость? на каком случае, скажем так, этот подход перестаёт работать?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> а как рекурсия ухудшает эту самую гибкость? на каком случае, скажем так, этот подход перестаёт работать?

Если говорить все-таки о гибкости, а не о строгой применимости, то очевидно, что проблемы с реализацией будут у функций, семантика параметров которых сильно зависит от их порядка в последовательности относительно других параметров.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

очевидно, что проблемы с реализацией будут у функций, семантика параметров которых сильно зависит от их порядка в последовательности относительно других параметров

мне неочевидно. поясни, откуда возникнут проблемы с реализацией

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Хорошо, простейший случай: хочу написать функцию, которая для каждого переданного ей объекта выведет на консоль результат некой выполненной над ним операции. При этом результат этой операции зависит от типа аргумента, будь то int, double или MyObject и общего кол-ва аргументов. Решая подобную задачу с помощью вариадических шаблонов, придется опять же прибегнуть к временному хранилищу, в худшем случае - к пресловутому std::list<boost::any>.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

функцию, которая для каждого переданного ей объекта выведет на консоль результат некой выполненной над ним операции

template<typename T>
void print_comma_separated_list(T value)
{
    std::cout<<value<<std::endl;
}

template<typename First,typename ... Rest>
void print_comma_separated_list(First first,Rest ... rest)
{
    std::cout<<first<<",";
    print_comma_separated_list(rest...);
}

первый шаблон можно специализировать по T, и задать какую-то особую обработку перед выводом для конкретных типов данных. в чём подвох?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Это понятно. Подвох в том, что общее кол-во этих аргументов, участвующее по условию в операции над ними, ты не узнаешь пока не обойдешь все элементы.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

общее кол-во этих аргументов, участвующее по условию в операции над ними, ты не узнаешь пока не обойдешь все элементы

имеется в виду вот это:

template <typename T, typename... Args>
struct count
{
  static const int value = 1 + count<Args...>::value;
};
const int args_size = count<int, char, bool, std::string>::value; // args_size == 4

или я, опять же, чего-то не понимаю? ну то есть да, для подсчёта количества элементов надо рекурсивно их обойти, но что в этом такого страшного? O(n), можно вызвать подсчёт элементов перед вызовом обработчика (если в этом действительно есть необходимость)

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Таким образом, остаются только проблемы с реализацией функций, результат которых зависит от положения аргументов относительно друг-друга. С другой стороны, если бы возможность произвольного доступа к параметрам вариадического шаблона была бы доступна, то и без того несладкий синтаксис шаблонов усложнился бы кардинально.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

остаются только проблемы с реализацией функций, результат которых зависит от положения аргументов относительно друг-друга

результат выполнения printf, очевидно, зависит от порядка следования аргументов. проблем с реализацией на вариадических шаблонах я не заметил

но вообще было бы интересно посомтреть на примеры таких функций - хотя бы парочку. есть у меня подозрение, что это слишком частная задача, чтобы её в принципе имело смысл решать на уровне базовых конструкций языка

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

Примером такой функции, например, является любая функция для которой нужна специализация по типу последнего аргумента. Не то что бы важная возможность, но и не «слишком частная задача».

mannaz ()

[C++] Переменное количество параметров в аргументах функции

функция для которой нужна специализация по типу последнего аргумента

почему этот аргумент нельзя поставить первым/перед typename...?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

почему этот аргумент нельзя поставить первым/перед typename...?

Можно. Но ты не находишь, что отсутствие возможности поставить этот аргумент после typename... - это проявление «негибкости»?

Для того, чтобы решить поставленную задачу существующими средствами понадобится код в духе

#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> AnyList;

template<typename T>
void helper (AnyList &list, const T &last)
{
    // generic...
}

template<>
void helper<> (AnyList &list, const long long &last)
{
    // specialized...
}

template<typename T, typename... Rest>
void helper (AnyList &list, const T &next, Rest... rest)
{
    list.push_back(next);
    helper(list, rest...);
}

template<typename... Args>
void function (Args... args)
{
    AnyList list;
    helper(list, args...);
}

int main (int argc, char* argv[])
{
    function(1, "hello", 2.2, 333LL);
}

Что-то подобное придется делать, если взаимосвязь между взаимным положением аргументов функции и операциями над ними сложнее, чем у printf.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

Но ты не находишь, что отсутствие возможности поставить этот аргумент после typename... - это проявление «негибкости»?

нет. было бы в C++ каррирование - я бы ещё понял, но так - нет. аналогично можно было бы сетовать на то, что аргументы со значениями по умолчанию также должны распологаться строго в конце списка аргументов

Что-то подобное придется делать

только в случае специальной обработки последнего элемента; но даже в этом случае - что тут настолько страшного? хотя применительно к данной задаче я не понимаю, зачем вообще может понадобится специализировать helper по последнему аргументу. в чём профит?

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> только в случае специальной обработки последнего элемента

В случаях, когда для обработки аргумента понадобятся значения аргументов, следующих до или после текущего. Иными словами, ограничения рекурсивного обхода параметров аналогичны ограничениям строго последовательного доступа в сравнении с произвольным.

аналогично можно было бы сетовать на то, что аргументы со значениями по умолчанию также должны распологаться строго в конце списка аргументов


Меня, в принципе, все устраивает: уже сейчас можно делать гораздо более интересные и практичные API. «Негибкость» в данном случае - это так... демагогия :)

mannaz ()

[C++] Переменное количество параметров в аргументах функции

В случаях, когда для обработки аргумента понадобятся значения аргументов, следующих до или после текущего

ты примеров функций так и не привёл, кстати

уже сейчас можно делать гораздо более интересные и практичные API

boost, массово переписанный на вариадические шаблоны, должен уменьшиться в размерах разов в пять-десять

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> ты примеров функций так и не привёл, кстати

Oh shi~, а пример со специализацией по последнему аргументу не прокатил что ли? Вполне себе зависимость обработки аргументов от значения последнего/предпоследнего/следующего-через-3-после-текущего.

разов в пять-десять


Ну это, конечно, очень смелая оценка. Мне в целом импонирует то, что c++0x позволит существенно сократить использование препроцессора в больших проектах.

mannaz ()

[C++] Переменное количество параметров в аргументах функции

Oh shi~, а пример со специализацией по последнему аргументу не прокатил что ли?

это был общий пример конструкции; я хочу пример её применения - ситуации, когда без такого не обойтись

Ну это, конечно, очень смелая оценка

про нутро boost.lambda в этом смысле готов спорить на ящик пива :)

jtootf ★★★★★ ()

[C++] Переменное количество параметров в аргументах функции

> я хочу пример её применения - ситуации, когда без такого не обойтись

Хм, ты требуешь невозможного. Любое ограничение C++, включая ограничения 0x, можно обойти множеством способов. В реальных условиях я не стал бы использовать подход, аналогичный приведенному выше. Это искусственная ситуация, случай, когда необходимость рефакторинга очевидна в момент написания кода.

Таким образом, предлагаю подождать, пока под c++0x со всеми его вариадическими шаблонами начнут перепиливать boost, чтобы посмотреть, какие костыли и для чего там придумают на этот раз :)

mannaz ()

[C++] Переменное количество параметров в аргументах функции

а в какой контейнер можно положить одновременно int, double, void *, и MyObject

с виртуальными функциями это делается в полпинка

вот пример статического списка без виртуальных функций

/// g++ -Wall multi-arg3.cxx && ./a.out
/// выхлоп:
/// int=2 char*=asdf double=1.5 char*=qqq


template<class L, class R>
struct Pair
{
  Pair(L l, R r): l(l),r(r) { }
  L l;
  R r;
  template<class RR> Pair<const Pair<const L&,const R&>&, const RR&> operator, (const RR& r) const
  {
    return pair(*this,r);
  }
};
template<class L, class R>
Pair<const L&, const R&> pair(const L& l, const R& r) { return Pair<const L&,const R&>(l,r); }

struct Nothing
{
  template<class R>  Pair<const Nothing&, const R&> operator, (const R& r) const /// <!!!> без const не пашет
  {
    return pair(*this,r);
  }
};
static const Nothing& NOTHING = Nothing();

template<class L, class R>
void do_something_with_all(const Pair<const L&, const R&>& arg)
{
  do_something_with(arg.l);
  do_something_with(arg.r);
}
template<class L, class LL, class R>
void do_something_with_all(const Pair<const Pair<const LL&, const L&>&, const R&> arg)
{
  do_something_with_all(arg.l);
  do_something_with    (arg.r);
}

/// /////////////////////////////////////////////////////////////////////////////// usage:

#include <iostream>

void do_something_with(const Nothing&) { }
void do_something_with(const int i)    { std::cout << " int=" << i; }
void do_something_with(const char* s)  { std::cout << " char*=" << s; }
void do_something_with(const double x) { std::cout << " double=" << x; }

int main()
{
  do_something_with_all(( NOTHING, 2, "asdf", 1.5, "qqq" ));
  std::cout << '\n';
  return 0;
}
www_linux_org_ru ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.