boost::lambda и перегруженные функции
От: Lomion  
Дата: 26.02.10 15:36
Оценка:
Всем доброго времени суток!

Столкнулся с одной проблемой:

struct Foo
{
    void foo (const std::string&)
    { }

    //void foo (int)
    //{ }
};

...
using boost::lambda::_1;
using boost::lambda::bind;

std::vector <Foo> vctr;
const std::string cnstnt = "";

std::for_each (vctr.begin (), vctr.end (), bind (&Foo::foo, _1, cnstnt));
...


Собстна, все работает, все понятно...
но, если расскомментировать в структуре метод foo с аргументом int, то все ломается — код не компилируется...
Как такое победить?

Заранее благодарен!!!
Re: boost::lambda и перегруженные функции
От: rg45 СССР  
Дата: 26.02.10 15:54
Оценка: 2 (1)
Здравствуйте, Lomion, Вы писали:

L>Всем доброго времени суток!


L>Столкнулся с одной проблемой:


L>
L>struct Foo
L>{
L>    void foo (const std::string&)
L>    { }

L>    //void foo (int)
L>    //{ }
L>};

L>...
L>std::for_each (vctr.begin (), vctr.end (), bind (&Foo::foo, _1, cnstnt));
L>...

L>


L>Собстна, все работает, все понятно...

L>но, если расскомментировать в структуре метод foo с аргументом int, то все ломается — код не компилируется...
L>Как такое победить?

При помощи явного приведения типа:
bind (static_cast<void (Foo::*)(const std::string&)>(&Foo::foo), _1, cnstnt);

Можно улучшить читабельность, использовав typedef:
typedef void (Foo::*F)(const std::string&);
bind(F(&Foo::foo), _1, cnstnt);
--
Re[2]: boost::lambda и перегруженные функции
От: igna Россия  
Дата: 26.02.10 16:06
Оценка: 3 (2) :)
Здравствуйте, rg45, Вы писали:

R>При помощи явного приведения типа:

R>bind (static_cast<void (Foo::*)(const std::string&)>(&Foo::foo), _1, cnstnt);


Здесь должен быть достаточен implicit_cast.
Re[3]: boost::lambda и перегруженные функции
От: rg45 СССР  
Дата: 26.02.10 16:51
Оценка:
Здравствуйте, igna, Вы писали:

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


R>>При помощи явного приведения типа:

I>
R>>bind (static_cast<void (Foo::*)(const std::string&)>(&Foo::foo), _1, cnstnt);
I>


I>Здесь должен быть достаточен implicit_cast.


ИМХО, неявное приведение сработает, если в точке использования однозначно определен целевой тип. А иначе приходится "подсказывать" при помощи явного приведения. Либо я твою мысль не уловил?
--
Re[4]: boost::lambda и перегруженные функции
От: igna Россия  
Дата: 26.02.10 16:57
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>ИМХО, неявное приведение сработает, если в точке использования однозначно определен целевой тип. А иначе приходится "подсказывать" при помощи явного приведения. Либо я твою мысль не уловил?


Я имел ввиду boost::implicit_cast. По-моему везде, где достаточен boost::implicit_cast нужно использовать его. Тем более, если Boost так и так используется.
Re[2]: boost::lambda и перегруженные функции
От: Lomion  
Дата: 26.02.10 17:25
Оценка:
Здравствуйте, rg45, Вы писали:

R>При помощи явного приведения типа:

R>
R>bind (static_cast<void (Foo::*)(const std::string&)>(&Foo::foo), _1, cnstnt);
R>

R>Можно улучшить читабельность, использовав typedef:
R>
R>typedef void (Foo::*F)(const std::string&);
R>bind(F(&Foo::foo), _1, cnstnt);
R>


Ммм... да, спасибо, я вроде бы понял... но, это был несколько искусственный пример...
в реальности, я так хотел использовать std::string::find... но что-то я, наверное, не до конца понял

    typedef std::string::size_type (std::string::*fnd_fnc) (const std::string&, std::string::size_type);

    std::vector <std::string> strings;
    std::for_each (strings.begin (), strings.end (), 
        bind (boost::implicit_cast <fnd_fnc> (&std::string::find), _1, cnstnt, 0));


Не компилится... Как это починить?
Re[3]: boost::lambda и перегруженные функции
От: rg45 СССР  
Дата: 26.02.10 22:05
Оценка: 1 (1)
Здравствуйте, Lomion, Вы писали:

L>...

L>Не компилится... Как это починить?

Модификатор const добавь и все образуется
  typedef std::string::size_type (std::string::*fnd_fnc) (const std::string&, std::string::size_type) const;
--
Re: boost::lambda и перегруженные функции
От: Кодт Россия  
Дата: 27.02.10 01:05
Оценка: 11 (2)
Здравствуйте, Lomion, Вы писали:

L>Как такое победить?


Причина, как уже сказали, в том, что у множества сигнатур — множество типов.
Поскольку bind не навязывает тип аргумента, а принимает всё что угодно, и возникла неоднозначность.

Конкретизировать тип можно двумя способами. Первый — указать сигнатуру.
Второй — позволить компилятору выбирать сигнатуры самостоятельно... Внимание, фокус!
struct Foo
{
  void foo() { cout << "foo()" << endl; }
  void foo(string s) { cout << "foo(\"" << s << "\")" << endl; }
  void foo(int n) { cout << "foo(" << n << ")" << endl; }
};

struct FooHelper
{
  typedef void result_type;
  result_type operator() (Foo* that) const { return that->foo(); }
  result_type operator() (Foo* that, string s) const { return that->foo(s); }
  result_type operator() (Foo* that, int n) const { return that->foo(n); }
};

int main()
{
  Foo f;
  FooHelper h;
  boost::bind(h, &f) ();
  boost::bind(h, &f, _1) ("hello");
  boost::bind(h, &f, _1) (123);
}

http://codepad.org/WPqb9i1a
Перекуём баги на фичи!
Re[2]: boost::lambda и перегруженные функции
От: Кодт Россия  
Дата: 27.02.10 01:17
Оценка:
А чтобы работало с искомым примером (for_each по вектору), надо, чтобы FooHelper::operator()(Foo& that,.....) — принимал не указатель, а ссылку.
Перекуём баги на фичи!
Re[2]: boost::lambda и перегруженные функции
От: jerry_ru  
Дата: 27.02.10 19:47
Оценка:
К>Второй — позволить компилятору выбирать сигнатуры самостоятельно... Внимание, фокус!
К>
К>struct Foo


Етить — зачет!

В boost::filesystem сталкивался часто.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.