Pull to refresh

Comments 16

Какое реальное применение данного объекта? В первый раз вижу потребность вызова классовых методов с обычными.
Какое реальное применение данного объекта?

Делегаты, например? Для чего обычно используется boost/std::function?

В первый раз вижу потребность вызова классовых методов с обычными.

Это не потребность, а возможность.
boost/std::function тоже позволяют связываться как со свободными функциями, так и с методами классов. Не вижу в этом ничего необычного, обе возможности могут пригодиться. Например, если обработчику не требуется состояние, зачем его делать методом класса, и наоборот, если состояние требуется, то простой функцией уже не обойтись.
Обе возможности могут пригодиться, да. Но вопрос в том — зачем унифицировать связывание?
Если речь непосредственно про связывание (BC_BIND(...) из статьи), то это непринципиально, просто унификация синтаксиса. А если про класс, инкапсулирующий указатель на функцию (bc::function<...>), то очевидно, что вызывающая сторона, которая хранит объекты этого класса, понятия не имеет, что именно к ней прицепит клиент, поэтому есть какой-никакой выбор.
Унифицировать — это само по себе правильно, и если есть выбор унифицировать или нет, конечно же лучше унифицировать.
А в данном случае — это еще и экономие кода и оперативки.
Где вы это реально применяете?

Ответ из двух частей:
1. Пишу это просто потому, что это возможно. Интересно поиграться с возможностями языка.
2. Похожая реализация (вариант для C++03, VS2010) в совокупности с умными указателями вынужденно применялась в системе сигнал/слот в одной компании, где не приветствовалась привязка не то, что к boost, но даже к stl.
Очень похоже на урезанные функторы (которые Александреску), почему бы не воспользоваться ими?
Вы не читали пост или не смотрели реализацию Loki::Functor, где используется динамическая аллокация памяти, от которой в данной реализации предлагается избавиться?
Статья не про то, что выбрать, а как еще можно сделать самому. Но если уж брать готовое, то лучше сразу из std или boost.
Так выходит все представить функцией :)
Действительно очень красиво — просто и гениально!
Люблю такие решения.
Пару советов:
1. Убрать бы макросы;
2. использовать не один указатель void* data_, а массив статичной длины на стеке, тогда можно делать как boost::bind, и распаковывать его (на этапе компиляции) в месте вызова. Например так
f(*static_cast<BINDED_ARGS*>(data_[INDEXES])...)

INDEXES — это pack длины BINDED_ARGS, вида <0, 1, ...>
Макросы ощутимо сокращают запись, указывается минимум необходимой информации: адрес функции и адрес объекта. Как написать так же кратко без них, не представляю.
Не понял, о чем речь во 2-м пункте. Это биндинг известных параметров к аргументам в момент связывания функции?
2. Да. Также как у вас создается обертка для члена класса можно передать и дополнительные аргументы.
Обертки для методов создаются на этапе компиляции и имеют статическое время жизни, т.е. доступны всегда. Это накладывает некоторые ограничения на код, например, нельзя инициализироваться из сырого указателя на метод класса, полученного через переменную, но это можно пережить. Многие же параметры имеют динамическую природу и вычисляются во время выполнения программы. Их не получится запаковать во время компиляции, т.к. актуальных значений еще не существует.

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

Sign up to leave a comment.

Articles