- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
#define CREATE_EVENT_LISTENER(_elname, arg1_type, arg1_name) \
class _elname : public EventListener \
{ \
private: \
class IContainer \
{ \
public: \
virtual void Call(arg1_type arg1_name) = 0; \
virtual ~IContainer() {} \
}; \
\
class FunctionContainer : public IContainer \
{ \
private: \
typedef void(*__CallbackPtr)(arg1_type); \
public: \
FunctionContainer(__CallbackPtr fn) \
{ \
this->fn = fn; \
} \
\
virtual void Call(arg1_type arg1_name) \
{ \
fn(arg1_name); \
} \
\
private: \
__CallbackPtr fn; \
}; \
\
template<class T, class Q> \
class MethodContainer : public IContainer \
{ \
public: \
MethodContainer(T method, Q _this) \
{ \
this->method = method; \
this->_this = _this; \
} \
\
virtual void Call(arg1_type arg1_name ) \
{ \
(_this->*method)(arg1_name); \
} \
\
private: \
T method; \
Q _this; \
}; \
public: \
typedef void(*__FN_CALLBACK)(arg1_type); \
\
_elname(__FN_CALLBACK fn) \
{ \
this->container = new FunctionContainer(fn); \
} \
\
template <class T, class Q> \
_elname(T method, Q _this) \
{ \
this->container = new MethodContainer<T, Q>(method, _this); \
} \
\
void Call(arg1_type arg1_name) \
{ \
container->Call(arg1_name); \
} \
\
virtual ~_elname() \
{ \
delete this->container; \
} \
private: \
IContainer* container; \
}; \
#define CREATE_EVENT(_ename, _elname, arg1_type, arg1_name) \
class _ename : public Event \
{ \
public: \
void AddListener(_elname* listener) \
{ \
Event::AddListener(listener); \
} \
\
void Handle(arg1_type arg1_name) \
{ \
for (size_t i = 0; i < this->listeners.size(); i++) \
{ \
((_elname*)listeners[i])->Call(arg1_name); \
} \
} \
\
void RemoveListener(_elname* listener) \
{ \
Event::RemoveListener(listener); \
} \
\
}; \
Я когда то это написал. Думал, это хорошая идея...
Полный файл: https://github.com/arhyme/CPP_EVENTS/blob/master/Event.h
Это такая обфускация?
не гони на табы.
они не виноваты в том что некоторые идиоты (ака: подавляющее большинство девелоперов) до 8 считать не умеют.
ЗЫ копи-пасти в VIM. потом ":set ts=4"
(3.1) Each identifier that contains a double underscore __ or begins with an underscore followed by an
uppercase letter is reserved to the implementation for any use.
(3.2) Each identifier that begins with an underscore is reserved to the implementation for use as a name in
the global namespace
Good job, fag.
Функция А имеет два разных определения в разных TU: А1 и А2.
А1 заинлайнилась в месте использования, а А2 компилер решил не инлайнить.
Линкер увидел что А — inline и взял первое попавшееся определение — А1.
Теперь код, который хотел вызвать А2 вызывает А1. И заметить это непросто.
(потестил на mingw. inline-определение перекрыло не инлайн-объявление, что по идее странно, но в остальном сработало предсказуемо)
статик инлайн.
обычные инлайн функции они просто обычные функции (с хинтом компилеру "плиз заинлайнь"), и если у тебя есть два определения в разных TU, то линкер пожалуется.
https://gcc.gnu.org/onlinedocs/gcc/Inline.html
PS из доки, единственная разница между inline vs always_inline это что последнее даже в дебуге будет заинлайнено.
> 8 апреля
Только не говори, что с тех пор ты повзрослел, набрался опыта, все переосмыслил и сейчас бы уже такое не сделал.
Это нормально? Т.е. такой объект можно будет как-то создать снаружи?
using my_int = int;
assert(is_same<my_int, int>); //Всегда true, в любую функцию ждущую my_int можно засунуть int
Утиная типизация — в шаблонах.
Может немножко крови попортить. Я думал, что только в сишке так.
с другой стороны, для того что бы твой пример работал, придется долго потрахатся, потому что как никрути, как долго секунды/минуты конвертятся в инты/из интов, строгой типизации у тебя ни как не получится. я в прошлом подобное делал с enum'ами и знакомые делали со структурами/классами - те же яйца: надо часто конвертить туда сюда, потому что иначе арифметика не работает. а потом появляются еще и ошибки типа `seconds_t S = 42; minutes_t M = minutes_t(to_int(S) + 1);` и начинают опускаться руки, потому что понимаешь что как ни крути, от ошибок не спасешься. (и даже в какой-то степени хуже получается, потому что меньше ожидаешь ошибок в таких местах, т.к. типа type-safe обертками пользуешься.)
Дык назови этот метод не to_int() а to_int_in_seconds() или seconds_as_int(). И говно сразу всплывёт на поверхность. Один хуй он нужен чуть менее чем никогда, поди только в реально низкоуровневых методах, поэтому длинное название никому не повредит...
З.Ы. А у нас вот тайпсейф обёртки неплохо код почистили от странных кастов, умножений и делений... И от раздумий "а в чём же эта хуйня измеряется", заодно.
> seconds_t S = 42
g:explicit
я просто хотел подчеркнуть что это не панацея.
абсолютные обёртки - (seconds_as_int() - мама, роди меня назад) - жутко не удобно использовать (сам не писал, но arbitrary precision кода в жабе насмотрелся). и чем дырявее/удобнее обертка, тем меньше гарантий она предоставляет.
Ты так часто скармливаешь кишки этих обёрток системным апишкам и сторонним либам? Ну вот в этих местах это будет отличным напоминанием о том, в чём измеряется их параметр.
А explicit конструктор - это страховка от злоебучих SetTimer(event, TimerRelative, 380), в которых потом хуй поймёшь, то ли автор реально хотел 38 микросекунд, то ли всё-таки 380, но забыл про особенность ёбаного EFI'шного таймера, и надо перелопатить кучу спецификаций, чтобы выяснить сколько там реально должно стоять...
sleep(int timeout)
Ладно в сишке средств минимум, но уж в плюсцах-то всё есть, чтобы сделать нормально.
У нас в кодбазе повсюду std::chrono::{seconds,milliseconds}, полёт нормальный, касты в инт ни разу не видел.
Лень гуглить, пора няшек смотреть и спать...
http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES#SetTimer.28.29
Тогда, я думаю, тебе понравится вот эта функция :3
Да, тут ещё лучше. И из сигнатуры сходу не понятно, спим for или until, и единицы измерения кучерявые.
> // минутка саморекламы
> https://habrahabr.ru/post/198568/
да делали мы уже все это - уже 15 лет назад.
в прошлом (сечас не пробовал) грабли были что эти прокладки добавляли код. по старой памяти, тестовый код без прокладки был на ~10% меньше чем код с прокладкой.
Ты про бинарный? Ну в дебаге прилично дуют, да, в основном из-за всяких ассёртов внутри операторов...
за годы много чего поменялось - может нынешнии компилеры умнее при выкидывании лишнего кода.
Ну акцессоры и конструкторы же в хедере были описаны, я надеюсь? Х.з., у меня сейчас всё выкидывает ;)
с прокладкой, или без прокладки (typedef int), GCC 4.8.2 генерит идентичный код, почти байт в байт.
так что можно пользоватся не напрягаясь.
к слову. я пропустил что твой IdOf другим целям служит.
почти с тем же эффектом, вместо `template <> class IdOf {}` я в прошлом пользовался enum'ами: С++ разные энумы сравнивать/присваивать не даёт. другими словами, вместо `typedef IdOf<Gadget> GadgetId;` я делал просто `enum GadgetId {}`. (потестировал: на сравнение разных энумов, g++ бросает ворнинг, а не ошибку.)
основное отличие в том что энумы в числа конвертируются без вопросов - без класса прокладки этого не запретить.
В старых плюсах нельзя выбрать underlying type у енума. Так что нужно как минимум ещё воткнуть в енум большую константу, чтобы компилятор взял достаточно широкий тип.
Кстати, там в комментах предлагали решение с enum class-ами, весьма годное, если юзать C++11.
и в числа они без явного приведения тоже не конвертируются. гугл говорит что преднамеренно. прогресс.
ЗЫ но все равно пидары: не добавили строковое представления для членов энумов...
А каст числа в енум случаем не UB, если в енуме не было такого числа?
An expression of arithmetic or enumeration type can be converted to an enumeration type explicitly. The value is unchanged if it is in the range of enumeration values of the enumeration type; otherwise the resulting enumeration value is unspecified.
З.Ы. А, in range, т.е. походу от минимального до максимального... Т.е. всё ок, если добавить в енум 0 и максимум.
Это Тор нужен чуть менее, чем никогда, а я нужен! У него молоко на губах не обсохло!
в том же примере что с минутами/секундами - делашь нормальных человеческий `struct myTime { int hours, mins, secs; /* + overloaded ops */ }` и все опять же работает. во многих случаях нежелание делать специализированые типы (и желание что то генерик/юниверсал сделать) и ведет к говнокодам.