C++11 рулить!
May. 4th, 2012 09:58 pmЗамутив на роботі круту шнягу із std::function, lambda, auto, std::bind і variadic templates.
Чесно кажучи, все це хак щоб обійти обмеження архітектури а-ля 90-ті. У нормальних умовах вистачило б std::bind.
Але сама можливість таких трюків надає відчуття всемогутності!
Всього-то треба було додати post-assign callback до певного application field. І все б нічого, тільки вказівник на об’єкт-holder має тип void *. Спочатку додав власне callback типу std::function<void (void *)>. Потім додав статичний метод-адаптер приблизно такий:
Роздільні типи Us і Vs потрібні для неявного перетворення типів (наприклад enum -> int). std::bind у temp потрібен бо gcc 4.6.1 ще не вміє захоплювати у лямбду пакунок параметрів і його треба зв’язати до передачі в лямбду.
Але ставити callback так:
appField.setPostAssignCallback(AppField::adaptMethod(&HoldSwap::setNotlDivMult, LEG1)) - не дуже зручно (хоча без адаптора було б гірше). Тому я ще зробив overload для setPostAssignCallback:
І тепер ставити callback можна просто:
appField.setPostAssignCallback(&HoldSwap::setNotlDivMult, LEG1);
Треба б ще параметри std::move-нути, але rvalue references не така проста штука як здається. Як буде час - напишу про них і про std::move/std::forward.
На фоні тупого багофіксингу писати таке було надзвичайно приємно. Головне щоб воно через рев’ю пройшло.
Чесно кажучи, все це хак щоб обійти обмеження архітектури а-ля 90-ті. У нормальних умовах вистачило б std::bind.
Але сама можливість таких трюків надає відчуття всемогутності!
Всього-то треба було додати post-assign callback до певного application field. І все б нічого, тільки вказівник на об’єкт-holder має тип void *. Спочатку додав власне callback типу std::function<void (void *)>. Потім додав статичний метод-адаптер приблизно такий:
template <class C, typename ... Us, typename ... Vs> std::function<void (void *)> adaptMethod(void (C::* method) (Us ...), Vs ... vs) { auto temp(std::bind(method, std::placeholders::_1, vs ...)); return [temp] (void * objPtr) { temp(static_cast<C *>(objPtr)); }; }
Роздільні типи Us і Vs потрібні для неявного перетворення типів (наприклад enum -> int). std::bind у temp потрібен бо gcc 4.6.1 ще не вміє захоплювати у лямбду пакунок параметрів і його треба зв’язати до передачі в лямбду.
Але ставити callback так:
appField.setPostAssignCallback(AppField::adaptMethod(&HoldSwap::setNotlDivMult, LEG1)) - не дуже зручно (хоча без адаптора було б гірше). Тому я ще зробив overload для setPostAssignCallback:
template <class C typename ... Us, typename ... Vs> void setPostAssignCallback(void (C::* method) (Us ...), Vs ... vs) { setPostAssignCallback(adaptMethod(method, vs ...)); }
І тепер ставити callback можна просто:
appField.setPostAssignCallback(&HoldSwap::setNotlDivMult, LEG1);
Треба б ще параметри std::move-нути, але rvalue references не така проста штука як здається. Як буде час - напишу про них і про std::move/std::forward.
На фоні тупого багофіксингу писати таке було надзвичайно приємно. Головне щоб воно через рев’ю пройшло.