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

ОГЛАВЛЕНИЕ

Упорядоченные операторы сравнения (новинка версии 1.4)

FastDelegates одного и того же типа теперь могут сравниваться с помощью <, >, <=, >=. Указатели функций-членов не поддерживают эти операторы, но их можно смоделировать с помощью простого двоичного сравнения путем использования memcmp(). Итоговая строгая квазиупорядоченность физически бессмысленна и зависима от компилятора, но она позволяет сохранять их в упорядоченных контейнерах, таких как std:set.

Класс DelegateMemento (новинка версии 1.4)

Новый класс DelegateMemento был создан, чтобы дать возможность иметь несопоставимые коллекции делегатов. В каждый класс FastDelegate были добавлены два дополнительных члена:

const DelegateMemento GetMemento() const;
void SetMemento(const DelegateMemento mem);

DelegegateMemento могут быть скопированы и сопоставлены друг с другом (==, !=, >, <, >=, <=), что позволит сохранить их в любом упорядоченном или неупорядоченном контейнере. Их можно использовать как замену для объединения указателей функций в C. Как и для объединения несопоставимых типов, вы обязаны убедиться в том, что вы используете один и тот же тип согласованно. Например, если вы получили DelegateMemento из FastDelegate2 и сохранили его в FastDelegate3, вероятно, ваша программа вызовет ошибку во время выполнения, когда вы вызовете ее. В будущем мы можем добавить режим отладки, использующий оператор typeid для обеспечения соблюдения безопасности типов. DelegateMemento в основном предназначены для использования в других библиотеках, а не в общем коде пользователя. Важная сфера применения – обмен сообщениями в Windows, где динамический std::map<MESSAGE, DelegateMemento> может заменить статические карты сообщений, найденные в MFC и WTL. Но это уже тема другой статьи.

Неявное преобразование в bool (новинка версии 1.5)

Теперь вы можете использовать синтаксис if (dg) {...} (где dg – это быстрый делегат) как альтернативу if (!dg.empty()), if (dg!=0) или даже if (!!dg). Если вы просто используете код, вы должны знать только то, что он работает правильно во всех компиляторах и случайно не выполняет другие действия.

Реализация была сложнее, чем ожидалось. Простое предоставление оператора bool опасно, так как он позволяет вам писать нечто вроде int a = dg; хотя вы, вероятно, имели в виду int a = dg();. Решение – использование преобразования в указатель данных закрытого члена вместо преобразования в bool. К сожалению, это может запутать синтаксис if (dg==0), и некоторые компиляторы реализуют указатели членов-данных с ошибками, поэтому нам пришлось использовать пару приемов. Один метод, который другие использовали раньше, - это разрешить сравнение с целыми числами, и ASSERT, если целое число не равно нулю. Вместо этого мы применяем более подробный метод. Единственный побочный эффект состоит в том, что сравнения с указателями функций становятся более оптимальными! Упорядоченные сравнения с константой 0 не поддерживаются (но действительно сравнение с указателем функции, который случайно оказывается пустым).