Указатели функций-членов и наиболее быстрые делегаты C++ - Использование кода

ОГЛАВЛЕНИЕ

Использование кода

Исходный код состоит из реализации FastDelegate (FastDelegate.h) и демонстрационного файла .cpp, поясняющего синтаксис. Чтобы использовать их в MSVC, создайте пустое консольное приложение и добавьте в него два данных файла. В GNU просто наберите "g++ demo.cpp" в командной строке.

Быстрые делегаты будут работать с любой комбинацией параметров, но чтобы заставить их работать в как можно большем числе компиляторов, вы должны указать число параметров при объявлении делегата. Есть максимальный предел в 8 параметров, но его не сложно увеличить. Используется пространство имен fastdelegate. Вся сложность заключена во внутреннем пространстве имен, названном detail.

Fastdelegates могут быть связаны с функцией-членом или со статической (свободной) функцией с помощью конструктора или bind(). По умолчанию они установлены в 0 (null). Их также можно установить в null с помощью clear(). Их можно проверить на равенство null, используя оператор ! или empty().

В отличие от большинства других реализаций делегатов, присутствуют операторы равенства (==, !=). Они будут работать даже в случае наличия встраиваемых функций.

Ниже приведена выдержка из FastDelegateDemo.cpp, показывающая большинство допустимых операций. CBaseClass – это виртуальный базовый класс CDerivedClass. Этот пример только лишь демонстрирует синтаксис.

 using namespace fastdelegate;

int main(void)
{
    // Поддерживаются делегаты с числом параметров не больше 8.
    // Здесь приведен случай функции, не имеющей типа.
    // Мы объявляем делегат и присоединяем его к SimpleVoidFunction()
    printf("-- FastDelegate demo --\nA no-parameter
             delegate is declared using FastDelegate0\n\n");             
           
    FastDelegate0 noparameterdelegate(&SimpleVoidFunction);

    noparameterdelegate();
    // вызываем делегат – при этом вызывается SimpleVoidFunction()

    printf("\n-- Examples using two-parameter delegates (int, char *) --\n\n");

    typedef FastDelegate2<int, char *> MyDelegate;

    MyDelegate funclist[10]; // инициализируются пустые делегаты
    CBaseClass a("Base A");
    CBaseClass b("Base B");
    CDerivedClass d;
    CDerivedClass c;
    
  // Связывание с простой функцией-членом
    funclist[0].bind(&a, &CBaseClass::SimpleMemberFunction);
  // также можно связывать со статическими (свободными) функциями
    funclist[1].bind(&SimpleStaticFunction);
  // и со статичексими функциями-членами
    funclist[2].bind(&CBaseClass::StaticMemberFunction);
  // и с постоянными функциями-членами
    funclist[3].bind(&a, &CBaseClass::ConstMemberFunction);
  // и с виртуальными функциями-членами.
    funclist[4].bind(&b, &CBaseClass::SimpleVirtualFunction);

  // Можно использовать оператор =. Для статических функций
  // fastdelegate выглядит аналогично простому указателю функции.
    funclist[5] = &CBaseClass::StaticMemberFunction;

  // Если класс производный,
  // нужно избегать указателей функций-членов.
  // Так же как и .bind(), вы можете применять
  // глобальную функцию MakeDelegate().
    funclist[6] = MakeDelegate(&d, &CBaseClass::SimpleVirtualFunction);

  // Наихудший случай – абстрактная виртуальная функция
  // виртуально-производного класса с как минимум одним невиртуальным базовым классом.
  // Это очень неясная ситуация, с которой вы вряд ли столкнетесь
  // в реальности, но она включена как испытание в предельном режиме.
    funclist[7].bind(&c, &CDerivedClass::TrickyVirtualFunction);
  // ...Но в таких случаях вы должны использовать базовый класс как
  // интерфейс. Следующая строка вызывает точно такую же функцию.
    funclist[8].bind(&c, &COtherClass::TrickyVirtualFunction);

  // можно выполнять связывание непосредственно с помощью конструктора
    MyDelegate dg(&b, &CBaseClass::SimpleVirtualFunction);

    char *msg = "Looking for equal delegate";
    for (int i=0; i<10; i++) {
        printf("%d :", i);
        // Операторы ==, !=, <=,<,>, and >= работают
        // Они работают даже для встроенных функций.
        if (funclist[i]==dg) { msg = "Found equal delegate"; };
        // Есть несколько способов проверить, пустой ли делегат
        // можно использовать if (funclist[i])
        // или          if (!funclist.empty())
        // или          if (funclist[i]!=0)
        // или          if (!!funclist[i])
        if (funclist[i]) {
            // Вызов генерирует оптимальный ассемблерный код.
            funclist[i](i, msg);
        } else {
            printf("Delegate is empty\n");
        };
    }
};