Вступ
Нещодавно при роботі над проектом навчальної практики виникла потреба з свого коду породжувати довільний процес і одночасно читати його stdout і stderr. Так як додаток пишеться виключно для linux, я вирішив заодно розібратися з epoll. Для запуску процесу на просторах інтернету була знайдена маленька бібліотека, робить саме те, що потрібно, та ще й обертаюча введення-виведення в звичні потоки із стандартної бібліотеки (мова про <iostream>).

Озброївшись кількома статтями про epoll, я вже було збирався писати код, якщо б не одне «але» — для epoll потрібний доступ до «сирим» файловим дескрипторам, а автор бібліотеки не надає public-доступу до них. Методи класу, повертають дескриптори, приховані під грифом «protected».

Що робити?
Найпростішим було б виправити код бібліотеки і перемістити потрібні методи public-секцію, ще краще було б форкнуть бібліотеку і реалізувати необхідний функціонал самому. Але перше було б негарно і обіцяло б конфліктами при оновленні бібліотеки, а друге зайняло б занадто багато часу на розбір коду бібліотеки і подальше тестування під кількома різними *nix-системами.

Тому в голову прийшла божевільна третя думка: чому б не спробувати як-то гарно «зламати» ООП і «легально» отримати доступ до protected-методом без втручання у вихідний код бібліотеки? Про те, які виникли перепони на цьому шляху і як допоміг C++14 в їх подоланні, і піде розповідь у даній публікації.

Читати далі →

Всім привіт! У статті буде представлена спрощена реалізацію
Stream
з Java 8 на С++. Скажу відразу, що:
  • на відміну від Java не використовуються відстрочені обчислень;
  • немає паралельних версій;
  • місцями поєднує
    Stream
    та
    Collectors
    ;
  • використовуються прості і готові рішення від STL, тут немає чистого ФП, де тільки рекурсія;
  • не використовуються техніки оптимізації.
В цій версії основний упор зроблений на те, щоб швидко і просто зробити велосипед). Про ФП згадано по-мінімуму (комбінаторам уваги не приділено :)).
Інтерфейс
template < typename Type>
class Stream : private StreamImpl<Type>
{
private:
typedef StreamImpl<Type> Parent;
public:
using Parent::Parent; // конструктори успадковані
using Parent::data;
using Parent::isEmpty;
using Parent::count;
using Parent::flatMap;
using Parent::map;
using Parent::reduce;
using Parent::filter;
using Parent::allMatch;
using Parent::noneMatch;
using Parent::groupingBy;
using Parent::partitionBy;
using Parent::minElement;
using Parent::maxElement;
~Stream() = default;
};

Читати далі →

Енну час тому в одній XMPP-кімнаті, присвяченій C++, один відвідувач запитав, чи немає якогось способу в сучасних плюси без зайвого коду передати вказівник на функцію-член класу в якості коллбека в C API. Ну, щось на зразок
// C API
void doWithCallback (void (*fn) (int, void*), void *userdata);

// C++ code
struct Foo
{
void doFoo (int param);
};

int main ()
{
Foo foo;
doWithCallback (MAGIC (/* &Foo::doFoo */), &foo);
}


Зрозуміло, що в якості
MAGIC
можна використовувати вільну функцію, статичну функцію-член або взагалі лямбду (2017-й рік на дворі, все-таки), але писати відповідну конструкцію кожен раз для кожної функції руками кілька ліниво, а препроцесор, як ми всі, звичайно, знаємо — моветон.

У цьому пості ми спробуємо (і, що характерно, у нас це вийде) написати універсальну обгортку, а заодно подивимося, як якась фішка з C++17 допоможе нам ще скоротити кількість надлишкового коду. Жодних крышесносных шаблонів тут не буде, рішення, на мій погляд, досить тривіально, але, мабуть, їм все одно має сенс поділитися (і заодно зайвий раз попіарити нові можливості C++17).


Читати далі →

dock: проста бібліотека модульного тестування коду на С++

Хоча і існують вже бібліотеки для юніт-тестування коду на С++, наприклад, Google Test або Bandit, а вони написані не мною тут воно, на мій погляд, якось переусложнено, порівняно з тим же JS. Там просто робиш, наприклад,
npm i mocha assert --save-dev
і можна приступати до написання тестів, а тут же треба це зробити ручками, а у випадку з
gtest
ще й зібрати з допомогою
cmake
. Bandit підключається просто, але не вміє в серіалізацію результатів у якійсь формат даних,
gtest
це вміє, але його потрібно збирати окремо. А я не хочу вибирати "або те, або це". Мені було потрібно зробити зручний і простий інструмент під мої завдання. Я хотів отримати просту бібліотеку без залежностей, header-only, на кілька файлів, яку можна легко і швидко підключити до свого проекту, зручно внести в неї зміни, якщо це буде необхідно). Але, найголовніше, мені хотілося отримувати зручні, машиночитані звіти, причому не тільки в
stdout
або
xml
, як в
gtest
), але і в будь-який інший формат, який я захочу. Далі під катом.
Читати далі →

Ідіома Ranges

image
Ідіома ranges — вкрай вдале розвиток ітераторів. Вона дозволяє писати високопродуктивний код, який не виділяє пам'ять, де це не треба, перебуваючи на гранично високому рівні абстракції. Крім того робить бібліотеки набагато більш універсальними, а їх інтерфейси гнучкими. Під катом короткий опис та практичні приклади використання ідіоми, тести продуктивності, а так само порівняння з популярними реалізаціями ітераторів C++ і C#.

Читати далі →

Універсальний конструктор Auto

З приходом C++11 з'явилася можливість оголошувати змінні типу auto, а компілятор сам визначив фактичний тип змінної, на основі типу инициализируемого значення. Це зручно, коли ми хочемо ініціалізувати змінну тип якої дуже складний, або невідомий, або він нам не дуже важливий, або просто для простоти.

Наприклад:

auto f = [](){}; //вказівник на функцію
auto r = foo(10); //тип повертається функцією foo
for (auto i = 0; i < 10; i++){} 

… і т. д. тобто в лівій частині рівності у нас автоматичний тип auto, а в правій частині значення чітко визначеного типу. А тепер уявімо, що у нас все навпаки:

int a = auto(10);

Читати далі →

Реліз CLion 2016.3: поліпшення підтримки C11, C++11 і C++14, зміни в роботі з проектною моделлю CMake і багато іншого

Привіт, Хабр! Рік потроху добігає кінця, хтось готується до святкових заходів, а хтось ще намагається завершити все задумане. А ми ось випустили третій за цей рік реліз нашої крос-платформної IDE для розробки на C та C++. Озираючись назад і підводячи підсумки, як прийнято робити напередодні нового року), нам здається, що за 2016 рік CLion істотно виріс і став набагато більш зрілим:

  • Як у плані мовної підтримки (variadic templates, auto-import і просто численні виправлення в частині аналізу коду),
  • Так і в плані різноманітних можливостей, що підвищують продуктивність розробки (нові опції кодогенерации, complete statement, рефакторинги в CMake),
  • Нових мов (Python, Swift),
  • Ну і, звичайно, інструментів, супутніх розробки на C та C++ (віддаленого налагодження і налагодження процесів, запущених не з IDE на локальній машині, підтримка формату документації коду Doxygen, безліч поліпшень в роботі з системами контролю версій).
Ми намагалися прислухатися до нашим користувачам (наскільки це було можливо) і орієнтуватися на їх запити. Версія 2016.3 не стала винятком і принесла безліч очікуваних поліпшень:

  • Крім відсутніх можливостей C++11, ми змогли, нарешті, почати підтримку можливостей стандартів C++14 C11.
  • Перероблений підхід до роботи з проектною моделлю CMake вирішив багато складнощів, з якими стикалися наші користувачі (від неможливості змінити директорію, в якій запускається генерація CMake, до проблем з продуктивністю і споживанням пам'яті).
  • Віддаленого налагодження можлива тепер і на платформі Windows.
  • У редакторі з'явилася семантична підсвічування.
  • Підвищена продуктивність при повторній індексації проектів на базі Unreal Engine, а ще ми вивчили поточний стан стороннього плагіна для генерації CMake для проектів на UE4 і написали про це цілий окремий пост.
  • Безліч інших поліпшень і змін.
image
А тепер про все по порядку.


Читати далі →

Використання сучасного С++ для підвищення продуктивності

У даній статті я хотів би розповісти, як використання засобів сучасних стандартів З++ дозволяє підвищити продуктивність програм без яких-небудь особливих зусиль від програміста.

Читати далі →

Аналітичне обчислення похідних на шаблонах C++

Тут днями писали про аналітичне знаходження похідних, що нагадало мені про моєї маленької бібліотечці на C++, яка робить майже те ж, але під час компіляції.



У чому профіт? Відповідь проста: мені потрібно було запрогать знаходження мінімуму досить складної функції, вважати похідні цієї функції за її параметрами ручкою на папірці було лінь, перевіряти потім, що я не опечатані при написанні коду, і підтримувати цей самий код — лінь подвійно, тому було вирішено написати штуковину, яка це зробить за мене. Ну, щоб в коді можна було написати щось таке:
using Formula_t = decltype (k * (_1 - r0) / (_1 + r0) * (g0 / (alpha0 - logr0 / Num<300>) - _1)); // формула
const auto residual = Formula_t::Eval (datapoint) - knownValue; // регресійний залишок

// похідні за параметрами:
const auto dg0 = VarDerivative_t<Formula_t, decltype (g0)>::Eval (datapoint);
const auto dalpha0 = VarDerivative_t<Formula_t, decltype (alpha0)>::Eval (datapoint);
const auto dk = VarDerivative_t<Formula_t, decltype (k)>::Eval (datapoint);

замість крокодилів, які вийдуть, якщо брати приватні похідні функції на картинці спочатку (вірніше, деякого її спрощеного варіанта, але він виглядає не так страшно).

Ще непогано бути достатньо впевненим, що компілятор це соптімізірует так, як якщо б відповідні похідні і функції були написані руками. А бути впевненим б хотілося — знаходити мінімум потрібно було дуже багато разів (дійсно багато, десь від сотні мільйонів до мільярда, в цьому була суть якогось обчислювального експерименту), тому обчислення похідних було б пляшковим горлечком, відбувається воно під час виконання через яку-небудь рекурсію по древообразной структурі. Якщо ж змусити компілятор обчислювати похідну, власне, під час компіляції, то є шанс, що він отриманого коду ще пройдеться оптимізатором, і ми не втратимо порівняно з ручним випискою всіх похідних. Шанс реалізувався, до речі.

Під катом — невеликий опис, як воно там все працює.


Читати далі →

Як уникнути помилок, використовуючи сучасний C++



Однією з проблем C++ є велика кількість конструкцій, поведінка яких не визначено або просто несподівано для програміста. З такими помилками ми часто стикаємося при використанні статичного аналізатора коду на різних проектах. Але, як відомо, краще знаходити помилки ще на етапі компіляції. Подивимося, які техніки з сучасного C++ дозволяють писати не тільки більш простий і виразний код, але і зроблять наш код більш безпечним і надійним.


Читати далі →