Передать группу перегруженных функций
От: igna Россия  
Дата: 27.01.12 17:23
Оценка:
Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?

То есть к примеру:

void f(int);
void f(char const*);

void g(int);
void g(char const*);

void h(generic_function const& gf)
{
    gf(1);
    gf("!");
}

int main()
{
    h(make_generic_function(f));
    h(make_generic_function(g));
}
Re: Передать группу перегруженных функций
От: night beast СССР  
Дата: 27.01.12 18:12
Оценка: 2 (1)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


сомнительно
разве что макросом. да и то, с ограничениями...
Re: Передать группу перегруженных функций
От: Константин Россия  
Дата: 27.01.12 18:23
Оценка: 2 (1)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


Возможная идея создать объект с несколькими перегруженными operator ()
— Думаю должно найтись шаблонное колдунство оборачивающие обычную функцию в правильный функциональный объект + обеспечить обёртки для комбинации нескольких функций
— Код клиента видимо придётся делать шаблонным по generic_function

#include <iostream>
#include <string>

template<typename F1, typename F2>
struct GenericFunctor2 : F1, F2
{
  using F1::operator();
  using F2::operator();
};

struct F1
{
  int operator() ( int i )
  {
    std::cout << "F1(int):" << i << std::endl;
    return i;
  }
};

struct F2
{
  void operator() ( const std::string& i )
  {
    std::cout << "F2(string):" << i << std::endl;
  }
};

typedef GenericFunctor2<F1,F2> ComplexFun;

template<typename F>
void test( F f )
{
  f(12);
  f("test");
}

int main()
{
  ComplexFun f;
  test(f);
  return 0;
}
Re: Передать группу перегруженных функций
От: Кодт Россия  
Дата: 27.01.12 18:59
Оценка: 5 (3)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


Может быть, сразу оформить группу перегруженных функций как единую сущность?
Такой сущностью будет, естественно, класс.
// самодостаточный
struct fs
{
  static void fun(int) { ... }
  static void fun(const char*) { ... }
};

// фасад к внешним функциям
struct gs
{
  template<class T> static void fun(T t) { g(t); }
};

template<class F> void h(F _ = F()) // аргумент - чтобы сработал вывод типов, а не только явно инстанцировать
{
  F::fun(1);
  F::fun("xxx");
}

Это если компайл-тайм.

А если рантайм, то как-то нужно победить полиморфизм аргументов.
Это может быть
— заранее известный набор типов, и тогда банально получаем интерфейс
struct IFun
{
  virtual void fun(int) const = 0;
  virtual void fun(const char*) const = 0;
};

void h(IFun& f)
{
  f.fun(123); f.fun("xxx");
}

— вариантный тип (VARIANT, boost::variant<...> или boost::any), и пусть функция сама парсит его
typedef void (*FUN)(boost::any const&);

void h(FUN f)
{
  f(123); f((const char*)"xxx");
}

void fs(boost::any const& x)
{
  if(x.type() == typeid(int)) { f(boost::any_cast<int>(x)); } else
  if(x.type() == typeid(const char*) { f(boost::any_cast<const char*>(x)); } else
  throw bad_argument(); // или что-то ещё
  // эту цепочку можно раскрутить с помощью списка типов boost::mpl, но я не хочу сейчас накручивать ещё и mpl
}
Перекуём баги на фичи!
Re: Передать группу перегруженных функций
От: Masterkent  
Дата: 27.01.12 22:02
Оценка: 3 (2) +1
igna:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


Это как раз одна из тех возможностей, которых в C++ весьма не хватает.
Re[2]: Передать группу перегруженных функций
От: Константин Россия  
Дата: 28.01.12 08:26
Оценка:
Здравствуйте, Masterkent, Вы писали:

I>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?

M>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.

Интересно, в какой ситуации это было бы полезно?
Re[2]: Передать группу перегруженных функций
От: Кодт Россия  
Дата: 29.01.12 11:47
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.


Вопрос в том, как эту возможность реализовать.
Либо мы добавляем интерпретатор. Передаём функцию по имени, далее интерпретатор находит подходящую сигнатуру, приводит типы аргументов, приводит тип результата, отстреливается при невозможности сделать что-либо из перечисленного.
Либо из каждой функции (ну, или не каждой, а специально помеченной) делаем мультиметод (интерпретатор в миниатюре). Передаём по адресу точки входа в мультиметод. Вызываем с вариантными типами, а диспетчерский код уже сам разбирается.
Либо устраиваем полиморфизм а-ля хаскелл (даже а-ля ML здесь не прокатит, — нам ведь нужна перегрузка). Но это совсем фантастика.

Кстати о мультиметодах.
Стоит посмотреть в сторону готовых библиотек, надстроек и языков.
Перекуём баги на фичи!
Re: Передать группу перегруженных функций
От: Юрий Жмеренецкий ICQ 380412032
Дата: 29.01.12 11:59
Оценка: 2 (1)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


boost.overload
Re: Передать группу перегруженных функций
От: Programador  
Дата: 29.01.12 11:31
Оценка: 2 (1)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?

void f(int);
void f(char const*);

void g(int);
void g(char const*);

struct PFun
{      typedef void (&t1)(int);
    t1 t1r;
    operator  t1  () { return g;}
        t2 t2r; 
    typedef void (&t2)(char const*);
    operator  t2  () { return t2r;}
} pf={f,g};

....
....
   pf("hkjhkjh");

ну или с указателями вместо ссылок
Re: Передать группу перегруженных функций
От: Programador  
Дата: 29.01.12 11:35
Оценка:
я человек из прошлого здесь такойже баг со временем поста http://rsdn.ru/forum/usability/4594574.1.aspx
Автор: Programador
Дата: 29.01.12
Re[3]: Передать группу перегруженных функций
От: Константин Россия  
Дата: 29.01.12 11:24
Оценка:
Здравствуйте, Кодт, Вы писали:

M>>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.

К>Вопрос в том, как эту возможность реализовать.

Всё-таки интересно, что может дать объединение семейства перегруженных функций в один объект, да ещё и на уровне core language?
— дало бы это экономию десятка/другого строк по сравнению с имитацией под конкретную задачу
— или это открыло бы Ящик Пандоры новые горизонты для метапрограммирования
Re[3]: Передать группу перегруженных функций
От: Masterkent  
Дата: 29.01.12 11:29
Оценка:
Константин:

I>>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?

M>>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.

К>Интересно, в какой ситуации это было бы полезно?


Например, в такой:

void f();
void f(int);

std::function<void()> fn = static_cast<void(*)()>(&f);

Если рассматривать более общую проблему, то можно также привести следующий пример:

void f(int = 0);
 
std::function<void()> fn = std::bind(&f, 0);

Вместо этих извращений со static_cast и std::bind можно было бы использовать простое выражение вроде []f, вычисляющееся в функтор, способный выбирать нужную функцию в зависимости от количества, типов и value categories передаваемых аргументов:

std::function<void()> fn = []f;
Re[4]: Передать группу перегруженных функций
От: m e  
Дата: 29.01.12 21:17
Оценка:
M>Если рассматривать более общую проблему, то можно также привести следующий пример:
M>
void f(int = 0);
M>std::function<void()> fn = std::bind(&f, 0);

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

вообще пожалуста поподробней, чего не хватает

скажем, boost::overload дает возможность задать functions.set(&f) ( https://svn.boost.org/svn/boost/sandbox/overload/trunk/libs/overload/docs/tutorial.qbk ); чего здесь не хватает, по-моему, это опять автоматической синхронизации строк
 functions.set( тут-указан-конкретный-вариант-из-перегрузок-функции-f );

с набором этих самых перегруженных вариантов функции f

вот примерно так, поподробней пожалуста

M>
void f();
void f(int);
std::function<void()> fn = static_cast<void(*)()>(&f);

мне не ясна не только цель, но и что тут происходить -- какая из f кастится?
Re[4]: Передать группу перегруженных функций
От: jazzer Россия Skype: enerjazzer
Дата: 29.01.12 21:42
Оценка:
Здравствуйте, Константин, Вы писали:

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


M>>>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.

К>>Вопрос в том, как эту возможность реализовать.

К>Всё-таки интересно, что может дать объединение семейства перегруженных функций в один объект, да ещё и на уровне core language?

К>- дало бы это экономию десятка/другого строк по сравнению с имитацией под конкретную задачу
К>- или это открыло бы Ящик Пандоры новые горизонты для метапрограммирования
double sqrt(double);
float sqrt(float);

std::vector<double> dvec;
std::vector<float> fvec;

for_each(double_vec, sqrt); // облом

template<class V1, class V2, class F>
void for_each2(V1& vec1, V2& vec2, F f)
{
  for_each( vec1, f );
  for_each( vec2, f );
}

for_each2( dvec, fvec, sqrt ); // облом

tuple< double, float > dft;
auto dft2 = for_each( dft, sqrt ); // облом

как видишь, никаких "новых горизонтов", код прозрачный и очевидный и должен работать как есть, независимо от того, перегружена функция или нет, плюс позволять откладывать разрешение перегрузки до раскрытия шаблона, как в примере с for_each2 и tuple.
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[2]: Передать группу перегруженных функций
От: jazzer Россия Skype: enerjazzer
Дата: 29.01.12 22:09
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, igna, Вы писали:


I>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


К>Может быть, сразу оформить группу перегруженных функций как единую сущность?

сразу неудобно и далеко не всегда возможно.

К>Такой сущностью будет, естественно, класс.

Угу, у меня макрос на эту тему есть, создает простой форвардер.
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[2]: Передать группу перегруженных функций
От: johny5 Новая Зеландия
Дата: 29.01.12 21:44
Оценка:
ЮЖ>boost.overload

Сигнатура у типа очень мутная, нужна "make" функции (для типа и значения). Иначе там и auto не поможет.
Re: Передать группу перегруженных функций
От: vic.scherba  
Дата: 19.09.14 23:35
Оценка: 9 (1)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


I>То есть к примеру:


I>
I>void f(int);
I>void f(char const*);

I>void g(int);
I>void g(char const*);

I>void h(generic_function const& gf)
I>{
I>    gf(1);
I>    gf("!");
I>}

I>int main()
I>{
I>    h(make_generic_function(f));
I>    h(make_generic_function(g));
I>}
I>


Без дополнительного runtime overhead с помощью одного из вспомогательных инструментов моей библиотеки:
#include <mml/inline_overloaded_fn/make_inline_overloaded_fn.hpp>

template <typename F>
void h(F const& gf)
{
    gf(1);
    gf("!");
}

// это приходится делать из-за неоднозначности имен
void(*f_int)(int) = &f;
void(*f_char)(char const*) = &f;

h(mml::make_inline_overloaded_fn(f_int, f_char));

// если вместо одного перегруженного имени f задать функциям различные имена, например f1 и f2, то все упростится до:
// h(mml::make_inline_overloaded_fn(f1, f2));

f_int = &g;
f_char = &g;

h(mml::make_inline_overloaded_fn(f_int, f_char));


С некоторым runtime overhead с помощью Boost.Functional/OverloadedFunction:
#include <boost/functional/overloaded_function.hpp>

template <typename F>
void h(F const& gf)
{
    gf(1);
    gf("!");
}

void(*f_int)(int) = &f;
void(*f_char)(char const*) = &f;

h(boost::make_overloaded_function(f_int, f_char));

f_int = &g;
f_char = &g;

h(boost::make_overloaded_function(f_int, f_char));


h при необходимости можно объявить не шаблонной.
Re: Передать группу перегруженных функций
От: jazzer Россия Skype: enerjazzer
Дата: 21.09.14 02:46
Оценка: 11 (3)
Здравствуйте, igna, Вы писали:

I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?


I>То есть к примеру:


  Скрытый текст
I>
I>void f(int);
I>void f(char const*);

I>void g(int);
I>void g(char const*);

I>void h(generic_function const& gf)
I>{
I>    gf(1);
I>    gf("!");
I>}

I>int main()
I>{
I>    h(make_generic_function(f));
I>    h(make_generic_function(g));
I>}
I>


Раз уж тему подняли из небытия, в С++14 это делается так:
void f(int);
void f(char const*);

auto h = [](auto gf) { gf(1); gf("!"); };

int main()
{
    h([](auto x){f(x);});
}

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[4]: Передать группу перегруженных функций
От: DmitryShm Россия  
Дата: 25.09.14 03:36
Оценка:
Здравствуйте, Константин, Вы писали:

К>Всё-таки интересно, что может дать объединение семейства перегруженных функций в один объект, да ещё и на уровне core language?


Это просто шаблон Посетитель (Visitor). Лично мне во всей этой истории не хватает именованных параметров в С++. Иначе все эти мультиметоды превращаются в очередной анти-шаблон, применение которого запутывает людей, читающих код. Если инкапсуляция мультиметода совпадает с какой-нибудь реальной сущностью в системе, то я создаю для этого отдельный класс. Иначе стараюсь обойтись понятными именами методов.
Re[2]: Передать группу перегруженных функций
От: Alexander G Украина  
Дата: 25.09.14 11:33
Оценка:
Здравствуйте, jazzer, Вы писали:

J>h([](auto x){f(x);});


J>


Ещё бы эту лямбду вариадиком с универсальной ссылкой...
Русский военный корабль идёт ко дну!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.