Перегрузка boost::function
От: Alexander G Украина  
Дата: 28.08.08 19:07
Оценка:
Захотелось что-то вроде boost::function, но чтобы оно хранило одновременно несколько функциональных объектов, и выбор осуществлялся в заисимости от аргументов — для иммитации перегрузки или параметров по умолчанию. Предполагается хранение до, допустим, шести объектов, в основном boost::bind.

Кто-нибудь думал о/сталкивался с/реализовывал подобное ? Какие будут идеи ?
Русский военный корабль идёт ко дну!
Re: Перегрузка boost::function
От: 0xDEADBEEF Ниоткуда  
Дата: 28.08.08 20:01
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Какие будут идеи ?

Естественно, написать аггрегат.
То есть:
class my_fancy_function
   :private std::function<[call-specification-1]>
   ,private std::function<[call-specification-2]>
   ....
   ,private std::function<[call-specification-N]>
{
// 
   using std::function<[call-specification-1]>::operator();
   ...
   using std::function<[call-specification-N]>::operator();
// единственный конструктор
   my_fancy_function() {} 
// инициализаторы - для всех вариантов вызова
   template<class T> void init_specifiction_1(T arg) 
      { static_cast< std::function<[call-specification-1]>& >(*this) = arg; }
};

//и profit!


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

Применение:
my_fancy_function f;

f.init_specification_1( &blah-blah );
f.init_specification_N( &blah-blah-foofack );
__________
16.There is no cause so right that one cannot find a fool following it.
Re: Перегрузка boost::function
От: Юрий Жмеренецкий ICQ 380412032
Дата: 28.08.08 23:26
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Захотелось что-то вроде boost::function, но чтобы оно хранило одновременно несколько функциональных объектов, и выбор осуществлялся в заисимости от аргументов — для иммитации перегрузки или параметров по умолчанию. Предполагается хранение до, допустим, шести объектов, в основном boost::bind.


AG>Кто-нибудь думал о/сталкивался с/реализовывал подобное ? Какие будут идеи ?


Соорудил такое:
void f1(const char*)  {    std::cout << "f1" << std::endl;}
void f2()             {    std::cout << "f2" << std::endl;}
void f3(int, int, int){    std::cout << "f3" << std::endl;}

template<class type>
void test(const type& f)
{
  f(1, 2); // f2
    
  f("abc"); // f1
    
  f(1,2,3); // f3
    
  // f(1); error
  // соответствие сигнатурам контролируется в compile-time
}

int main()
{
  boost::function<void(const char*)>   fn1 = boost::bind(f1, _1);
  boost::function<void(int, int)>      fn2 = boost::bind(f2);
  boost::function<void(int, int, int)> fn3 = boost::bind(f3, _1, _2, _3);
    
  test(
    (join << fn1 << fn2 << fn3)
  );
}

Реализация правда, восторга не вызывает. Постить пока не буду...
Re: Перегрузка boost::function
От: jazzer Россия Skype: enerjazzer
Дата: 29.08.08 05:47
Оценка: 41 (2)
Здравствуйте, Alexander G, Вы писали:

AG>Захотелось что-то вроде boost::function, но чтобы оно хранило одновременно несколько функциональных объектов, и выбор осуществлялся в заисимости от аргументов — для иммитации перегрузки или параметров по умолчанию. Предполагается хранение до, допустим, шести объектов, в основном boost::bind.


AG>Кто-нибудь думал о/сталкивался с/реализовывал подобное ? Какие будут идеи ?


(шепотом) boooooosssssst

конкретно, Boost.Overload.
Она еще не включена, так что бери из vault, доки здесь: http://docs.google.com/Doc?id=dhd386mp_16gxsfxn&amp;invite=gdr7gtq (не могу обещать, что линк работает — у нас на работе гугль забанен), так что, на всякий случай, вот примеры использования, оно?
(ниже идет порядка 200 строк кода)



/*
    Author: Marco Costalba (C) 2007-2008


 To compile:

    (gcc)  g++ -O2 -o test test.cpp
    (MSVC) cl /Ox /EHs test.cpp


 An overload it's a multi-signature function wrapper.

 Once defined on a set of signatures it is possible to assign with
 overload::set<>() any function, function object or even pointer
 to member function to the overload as long as the signature
 of the assigned function/functor matches one of the overload's
 signatures set.

 It is possible to assign many functions/functors as long as each
 one has a different signature, otherwise the latest assignment
 overwrites the earlier with the same signature.

 Overload uses copy semantic for functors, so that a copy of the
 assigned functor is stored. This implies that functors must be copy
 constructible.

 An overload supports value semantic itself being copy constructible
 and assignable.

 When overload is invoked the calling arguments are forwarded to the
 correct assigned function, an overload_ns::bad_function_call exception
 will be thrown if the corresponding signature slot is empty.

 User can call overload::is_set<Sig>() to check if slot corresponding
 to signature Sig is empty.

 Finally user can clear a slot corresponding to signature Sig with
 overload::reset<Sig>()

 Internally, given a set of signatures, overload instantiates a hierarchy
 of classes, one per signature, and each class defines an operator()
 that interface a given signature and forwards it's arguments to the
 assigned function/functor.

 When an overload is called compiler will link the correct operator()
 according to the argument's type and arity.

 Overload signatures rules should follow strictly what states C++ for
 overloading of operator() member functions, so as example if an overload
 is called with an argument for which no exact match occurs, but that can
 be converted by more then one overloaded operator() then a compile error
 occurs of type 'ambiguous call'.

 Anyhow implicit conversions at invocation time are supported as long as
 there is no ambigity on the function to call.

 Overload code is self contained, no external libraries are needed apart
 from the standard one.

 Because overloads support value semantic it is possible to store them in
 any kind of container to obtain a very powerful and flexible dispatcher.

 Following examples will clarify overload usage.
*/
#include "overload.hpp"

#include <cassert>
#include <iostream>
#include <string>
#include <map>

using std::string;

int foo1(char) { return -1; }

double foo2(int, char) { return 123.456; }

char foo3(string) { return 'x'; }

void foo4(string s1, string s2, string s3) { std::cout << s1 + s2 + s3; }

int foo5() { return 7; }

template<typename T>
T fooT(T const& t) { return -t; }

struct foo1_t
{
    int operator()(char) { return 123; }
    int operator()(char) const { return 123; }

    char foo3(string) { return 'y'; }
    int foo1(char) { return 8; }

    static char foo3_s(string) { return 's'; }
};

int main(int, char**)
{
    overload_ns::overload
    <   int(char)
      , double(int, char)
      , int()
      , double(double const&)
      , void(string, string, string)
      , char(string)
    > f(foo4, &foo1, fooT<double>);  /* Assign functions directly in the c'tor */

    /* Use is_set() to check if a given signature slot is empty */
    assert( f.is_set<int(char)>() == true );

    assert( f.is_set<int()>() == false );

    typedef int (Fun)();
    Fun* foo5_ptr(foo5);
    Fun& foo5_ref(foo5);

    /* Assign functions in any order as pointers, references or plain types */
    f.set(&foo2);
    f.set(foo5_ptr);
    f.set(foo5_ref);
    f.set(foo3);

    assert( f('x') == -1 );

    /* Assign functors as well as pointers, references or plain types */
    foo1_t functor;
    foo1_t& functor_ref(functor);

    f.set(&functor); // overwrites foo1()
    f.set( functor);
    f.set( functor_ref);

    /* Works also with const objects */
    const foo1_t const_functor(functor);

    f.set(&const_functor);
    f.set( const_functor);

    /* Implicit conversions are supported at invocation time */
    f("\nHello", " World", " I'm Marco\n");

    assert( f('x') == 123 );
    assert( f(123, 'x') > 123.455 && f(123, 'x') < 123.457 );
    assert( f("hello") == 'x' );
    assert( f() == 7 );
    assert( f(-3.0) > 2.9 && f(-3.0) < 3.1 );

    /* Try with static member function */
    f.set(foo1_t::foo3_s);

    assert( f("hello") == 's' );

    /* Assign a pointer to member function */
    f.set(&functor, &foo1_t::foo3); // overwrites foo3()
    f.set( functor, &foo1_t::foo1); // overwrites functor.operator()

    assert( f("hello") == 'y' );
    assert( f('x') == 8 );

    /* Finally, it is possible to reset a given signature */
    assert( f.is_set<int(char)>() == true );

    f.reset<int(char)>();

    assert( f.is_set<int(char)>() == false );

    /* An exception is thrown if an empty slot is called */
    try {
        f('x');
        assert(false); // fail if we arrive here
    }
    catch (overload_ns::bad_function_call& e)
    {
        std::cout << std::endl << e.what() << std::endl;
    }

    /* An overload is copy constructible and assignable */
    typedef overload_ns::overload<  int(char)
                                  , double(int, char)
                                  , int()
                                  , double(double const&)
                                  , void(string, string, string)
                                  , char(string)
                                 > Overload;
    Overload h(f), g;

    assert( h(123, 'x') > 123.455 && h(123, 'x') < 123.457 );
    assert( h("hello") == 'y' );

    g = h;

    assert( g(123, 'x') > 123.455 && g(123, 'x') < 123.457 );
    assert( g("hello") == 'y' );

    /* Because of value semantic we can store them in an array */
    Overload d[5];

    d[0].set(foo1);
    d[1].set(functor, &foo1_t::foo1);

    assert( d[0]('x') == -1 );
    assert( d[1]('x') == 8 );

    /* Any container is suitable, as example a std::map, so to
     * easily obtain a powerful runtime dynamic dispatcher with
     * multi-signature (heterogeneous function types) support.
     */
    std::map<string, Overload> m;

    m["First"] = g;
    m["Second"] = Overload(foo3, foo1);

    m["First"].set(functor, &foo1_t::foo1);

    assert( m["First"]('x') == 8 );
    assert( m["Second"]('x') == -1 );

    assert( m["First"]("hello") == 'y' );
    assert( m["Second"]("hello") == 'x' );

    std::cout << "\nTest successful\n" << std::endl;

    return 0;
}
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]: Перегрузка boost::function
От: Юрий Жмеренецкий ICQ 380412032
Дата: 29.08.08 06:28
Оценка: 12 (1)
Здравствуйте, jazzer, Вы писали:

J>(шепотом) boooooosssssst




Вот еще из boost::vault: Multi signature boost::function extension


typedef boost::mpl::vector<int(char), char(string)> Signatures;

int foo1(char) { return -1; }

struct foo2_t { char operator()(std::string) const { return 'x'; }};

//...

msf::function<Signatures> f;

foo2_t foo2;
f = foo1;
f = foo2;

std::cout << f('x') << std::endl; // foo1 will be called
std::cout << f("hello") << std::endl; // foo2::operator() will be called
Re[3]: Перегрузка boost::function
От: Юрий Жмеренецкий ICQ 380412032
Дата: 29.08.08 06:37
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Здравствуйте, jazzer, Вы писали:


J>>конкретно, Boost.Overload


ЮЖ>Вот еще из boost::vault: Multi signature boost::function extension


Похоже что это одно и тоже, только overload_ns::overload заменен на mpl::vector...
Re[2]: Перегрузка boost::function
От: Alexander G Украина  
Дата: 29.08.08 08:03
Оценка:
Здравствуйте, jazzer, Вы писали:

J>вот примеры использования, оно?


оно

интерфейс соответствует всем моим пожеланиям:
1. Type erasure. Т.е. возможность затайпдефить typedef boost::overload<int (void), void(int)> my_callback; (нужно было именно это, а не выводимый тип, вроде boost::bind)
2. Метод set с шаблонным параметром сигнатурой. Выводит шаблонный параметр из boost::function, boost::bind и других функторов.
3. Конструктор, в котором можно перечислять функции в произвольном порядке.

J>доки здесь: http://docs.google.com/Doc?id=dhd386mp_16gxsfxn&amp;invite=gdr7gtq

Работает, надо только залогинится в гугл.
Сама либа здесь.

Всё уже украдено до меня, что и следовало ожидать
Русский военный корабль идёт ко дну!
Re[2]: Перегрузка boost::function
От: Alexander G Украина  
Дата: 29.08.08 08:43
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>void f1(const char*)  {    std::cout << "f1" << std::endl;}
ЮЖ>void f2()             {    std::cout << "f2" << std::endl;}
ЮЖ>void f3(int, int, int){    std::cout << "f3" << std::endl;}

ЮЖ>template<class type>
ЮЖ>void test(const type& f)
ЮЖ>{
ЮЖ>  f(1, 2); // f2
    
ЮЖ>  f("abc"); // f1
    
ЮЖ>  f(1,2,3); // f3
    
ЮЖ>  // f(1); error
ЮЖ>  // соответствие сигнатурам контролируется в compile-time
ЮЖ>}

Это не то что я хочу.
Нужен не вроде boost::bind, т.е. выводимый тип, а нечто, что можно затайпдефить и использовать в качестве формального параметра виртуальной функции. То что называют "type erasure". Т.е. test д.б. не-шаблонной.
ЮЖ>int main()
ЮЖ>{
ЮЖ>  boost::function<void(const char*)>   fn1 = boost::bind(f1, _1);
ЮЖ>  boost::function<void(int, int)>      fn2 = boost::bind(f2);
ЮЖ>  boost::function<void(int, int, int)> fn3 = boost::bind(f3, _1, _2, _3);
    
ЮЖ>  test(
ЮЖ>    (join << fn1 << fn2 << fn3)
ЮЖ>  );
ЮЖ>}


Временные boost::function не очень удобно, хотелось передавать boost::bind напрямую.
Лучше обычный метод, а не оператор, чтобы можно было задать сигнатуру явно.

ЮЖ>Реализация правда, восторга не вызывает. Постить пока не буду...

Свою я тоже не запосчу. Уже посмотрел на Boost.Overload
Русский военный корабль идёт ко дну!
Re[2]: Перегрузка boost::function
От: Alexander G Украина  
Дата: 29.08.08 08:46
Оценка:
Здравствуйте, 0xDEADBEEF, Вы писали:

DEA>Здравствуйте, Alexander G, Вы писали:


DEA>class my_fancy_function
DEA>   :private std::function<[call-specification-1]>
DEA>   ,private std::function<[call-specification-2]>
DEA>   ....
DEA>   ,private std::function<[call-specification-N]>
DEA>{
DEA>// 
DEA>   using std::function<[call-specification-1]>::operator();
DEA>   ...
DEA>   using std::function<[call-specification-N]>::operator();

Это надо несколько раз упоминать каждую при объявлении типа ? Или предлагается использовать какую-либо хотрую препроцессорную магию ? не, не то.

И С++0х для меня пока ещё светлое будущее.
DEA>// единственный конструктор
DEA>   my_fancy_function() {}

про конструктор ниже.
DEA>// инициализаторы - для всех вариантов вызова
DEA>   template<class T> void init_specifiction_1(T arg) 
DEA>      { static_cast< std::function<[call-specification-1]>& >(*this) = arg; }
DEA>};

а почему бы не выводить сигнатуру из шаблонного параметра, зачем мне эти _1 ?
DEA>//и profit!


Слишком много ??????????? до профита.

DEA>Но, есть одна тонкость, если начать пытаться писать конструкторы, то получится черт-те что. В аггрегате могут начать инициализироваться не те подклассы.

DEA>Посему, не стоит делать инициализирующие конструкторы, которые будут "сами" выбирать вариант инициализации. Лучше сделать набор инициализирующих функций, которые и надо вызывать для этого.



DEA>Применение:

DEA>
DEA>my_fancy_function f;

DEA>f.init_specification_1( &blah-blah );
DEA>f.init_specification_N( &blah-blah-foofack );

А я не вижу, почему выбор вариантов инициализации может быть ошибочен. Можно однозначно вывести сигнатуру, и такая сигнатура есть — инициализируем, явно дали сигнатуру — тоже инициализируем, иначе — фэйл на этапе компиляции. вот у Boost.Overload это вроде удалось.
Русский военный корабль идёт ко дну!
Re[3]: Перегрузка boost::function
От: Alexander G Украина  
Дата: 29.08.08 16:11
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Здравствуйте, jazzer, Вы писали:


J>>(шепотом) boooooosssssst


ЮЖ>)


ЮЖ>Вот еще из boost::vault: Multi signature boost::function extension


А ведь судя по датам MSF это более новая Boost.Overload, таки наверное её и заюзаем.
Русский военный корабль идёт ко дну!
Re[4]: Перегрузка boost::function
От: jazzer Россия Skype: enerjazzer
Дата: 29.08.08 17:20
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>А ведь судя по датам MSF это более новая Boost.Overload, таки наверное её и заюзаем.


даты тут плохой советчик.
лучше мейл-лист смотреть на предмет обсуждения (я не смотрел, не до того), там обычно, прежде чем предложить библиотеку в буст, забрасываются удочки на предмет изучения интереса сообщества.
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[5]: Перегрузка boost::function
От: Alexander G Украина  
Дата: 29.08.08 19:05
Оценка:
Здравствуйте, jazzer, Вы писали:

J>лучше мейл-лист смотреть на предмет обсуждения (я не смотрел, не до того), там обычно, прежде чем предложить библиотеку в буст, забрасываются удочки на предмет изучения интереса сообщества.


Из недавних упоминаний — только вот.
MSF действительно более новая.
Русский военный корабль идёт ко дну!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.