C ++ странный синтаксис обнаружен в параметрах шаблона Boost - PullRequest
8 голосов
/ 27 июня 2010

Я просматривал документацию по классу «Функции» в Boost и наткнулся на это:

boost::function<float (int x, int y)> f;

Я должен признать, что этот синтаксис меня сильно смущает.Как это может быть законно C ++?

Есть ли какой-нибудь трюк под капотом?Этот синтаксис задокументирован где-нибудь?

1 Ответ

9 голосов
/ 27 июня 2010

[Редактировать] Это ответ на оригинальный, неотредактированный вопрос автора, который был фактически двумя вопросами.

Я должен признать, что этот синтаксис очень сбивает с толку для меня. Как это может быть легальный 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, которое использовалось бы многими людьми на многих платформах и компиляторах. Тем не менее, они не пытались обобщить систему команд, способную выполнять функции с разными сигнатурами в единой системе отмены (таким образом, требуя сохранения состояния этих команд даже после того, как одна из них первоначально закончила вызывать их и иметь возможность отменить и повторно - выполнять их без повторного указания исходных данных о состоянии при последующих выполнениях). Для этого ваш подход, основанный на наследовании, скорее всего, лучший и самый простой.

...