C++ странный синтаксис обнаружен в параметрах шаблона Boost
Я просматривал документацию по классу "Функции" в Boost и наткнулся на это:
boost::function<float (int x, int y)> f;
Я должен признать, что этот синтаксис очень сбивает меня с толку. Как это может быть законным C++?
Есть ли какая-то хитрость под капотом? Этот синтаксис задокументирован где-нибудь?
1 ответ
[Редактировать] Это ответ на оригинальный, неотредактированный вопрос автора, который был фактически двумя вопросами.
Я должен признать, что этот синтаксис очень сбивает меня с толку. Как это может быть законным 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.
Тем не менее, я хочу решить вашу общую проблему. Я думаю, что вы слишком стараетесь упростить пару строк совершенно приемлемого кода. Нет ничего плохого в передаче аргументов для ваших подклассов команд через их параметризованные конструкторы подклассов. Стоит ли пытаться задействовать здесь списки типов и решения типа boost::function, тем самым значительно увеличивая время компиляции и сложность кода, просто для этого?
Если вы хотите уменьшить его еще больше, просто напишите функцию 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, которое использовалось бы многими людьми на многих платформах и компиляторах. Тем не менее, они не пытались обобщить систему команд, способную выполнять функции с разными сигнатурами в единой системе отмены (таким образом, требуя сохранения состояния этих команд даже после того, как одна из них первоначально закончила вызывать их и была в состоянии отменить и перезапустить - выполнять их без повторного указания исходных данных о состоянии при последующих выполнениях). Для этого ваш подход, основанный на наследовании, скорее всего, самый лучший и самый простой.