Здравствуйте, igna, Вы писали: I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра? I>То есть к примеру:
— вариантный тип (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
}
Здравствуйте, igna, Вы писали:
I>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?
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));
Здравствуйте, 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;
}
Здравствуйте, Masterkent, Вы писали:
I>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра? M>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.
Здравствуйте, Кодт, Вы писали:
M>>Это как раз одна из тех возможностей, которых в C++ весьма не хватает. К>Вопрос в том, как эту возможность реализовать.
Всё-таки интересно, что может дать объединение семейства перегруженных функций в один объект, да ещё и на уровне core language?
— дало бы это экономию десятка/другого строк по сравнению с имитацией под конкретную задачу
— или это открыло бы Ящик Пандоры новые горизонты для метапрограммирования
Константин:
I>>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра? M>>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.
К>Интересно, в какой ситуации это было бы полезно?
Вместо этих извращений со static_cast и std::bind можно было бы использовать простое выражение вроде []f, вычисляющееся в функтор, способный выбирать нужную функцию в зависимости от количества, типов и value categories передаваемых аргументов:
Здравствуйте, Masterkent, Вы писали:
M>Это как раз одна из тех возможностей, которых в C++ весьма не хватает.
Вопрос в том, как эту возможность реализовать.
Либо мы добавляем интерпретатор. Передаём функцию по имени, далее интерпретатор находит подходящую сигнатуру, приводит типы аргументов, приводит тип результата, отстреливается при невозможности сделать что-либо из перечисленного.
Либо из каждой функции (ну, или не каждой, а специально помеченной) делаем мультиметод (интерпретатор в миниатюре). Передаём по адресу точки входа в мультиметод. Вызываем с вариантными типами, а диспетчерский код уже сам разбирается.
Либо устраиваем полиморфизм а-ля хаскелл (даже а-ля ML здесь не прокатит, — нам ведь нужна перегрузка). Но это совсем фантастика.
Кстати о мультиметодах.
Стоит посмотреть в сторону готовых библиотек, надстроек и языков.
я правильно понял, что проблема тут в том, что "0" в последней строке невозможно синхронизировать автоматически с "0" в первой строке? т.е. если "0" в первой строке изменят, то "0" во второй могут забыть изменить, и получить ошибку
Здравствуйте, Константин, Вы писали:
К>Здравствуйте, Кодт, Вы писали:
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.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, igna, Вы писали:
I>>Как "одним движением" зацепить и передать группу перегруженных функций в качестве фактического параметра?
К>Может быть, сразу оформить группу перегруженных функций как единую сущность?
сразу неудобно и далеко не всегда возможно.
К>Такой сущностью будет, естественно, класс.
Угу, у меня макрос на эту тему есть, создает простой форвардер.
Здравствуйте, Константин, Вы писали:
К>Всё-таки интересно, что может дать объединение семейства перегруженных функций в один объект, да ещё и на уровне core language?
Это просто шаблон Посетитель (Visitor). Лично мне во всей этой истории не хватает именованных параметров в С++. Иначе все эти мультиметоды превращаются в очередной анти-шаблон, применение которого запутывает людей, читающих код. Если инкапсуляция мультиметода совпадает с какой-нибудь реальной сущностью в системе, то я создаю для этого отдельный класс. Иначе стараюсь обойтись понятными именами методов.