[Редактировать] Это ответ на оригинальный, неотредактированный вопрос автора, который был фактически двумя вопросами.
Я должен признать, что этот синтаксис очень
сбивает с толку для меня. Как это может быть
легальный C ++? :) Есть ли хитрость
под капотом ? Это синтаксис
задокументировано где-нибудь?
Это совершенно законно и на самом деле не слишком сложно.
template <class T>
class C
{
public:
T* function_pointer;
};
void fn(int x)
{
cout << x << endl;
}
int main(int argc, char** argv)
{
C<void (int x)> c;
c.function_pointer = &fn;
c.function_pointer(123); // outputs x
}
Это в основном то же самое, что и делать:
typedef void Function(int);
C<Function> c;
Этот тип применим не только к C ++, он также применим к C (фактический тип C параметризован). Волшебство шаблона здесь берет что-то вроде функции typedef и может определять типы возвращаемых значений и аргументов. Объясняя, что это будет слишком длинно, и boost :: function использует множество мета-шаблонов функций в boost для получения этой информации. Если вы действительно хотите потратить время на изучение этого, вы должны попытаться понять реализацию boost, начиная с boost :: function_traits в Boost.Type Traits.
Однако я хочу решить вашу общую проблему. Я думаю, вы слишком стараетесь упростить пару строк совершенно приемлемого кода. Нет ничего плохого в передаче аргументов для ваших подклассов команд через их параметризованные конструкторы подклассов. Действительно ли стоит пытаться задействовать здесь списки типов и повысить :: функциональные решения, тем самым значительно увеличивая время компиляции и сложность кода, просто для этого?
Если вы хотите уменьшить его еще больше, просто напишите функцию execute, которая будет выполнять любой подкласс команд, и добавьте ее в стек отмены и так далее:
typedef boost::shared_ptr<Command> CommandPtr;
void execute(const CommandPtr& cmd)
{
cmd->execute();
// add command to undo stack or whatever else you want to do
}
// The client can simply write something like this:
execute(CommandPtr(new CmdAdd(some_value) );
Я действительно думаю, что компромисс между попыткой усложнить ситуацию не стоит. Авторы надстройки хотели написать чрезвычайно универсальное решение для boost :: function, которое использовалось бы многими людьми на многих платформах и компиляторах. Тем не менее, они не пытались обобщить систему команд, способную выполнять функции с разными сигнатурами в единой системе отмены (таким образом, требуя сохранения состояния этих команд даже после того, как одна из них первоначально закончила вызывать их и иметь возможность отменить и повторно - выполнять их без повторного указания исходных данных о состоянии при последующих выполнениях). Для этого ваш подход, основанный на наследовании, скорее всего, лучший и самый простой.