Заниманительная частичная специализация шаблонов

Занимаясь одним из своих проектов, случайно для себя обнаружил, что частично специализировать вложенные шаблонные классы можно параметрами шаблонов, в которые они вложены. Например у нас есть шаблонный класс nested, вложенный в шаблонный класс str: template <typename X1, typename Y1> struct str { template <typename X2, typename Y2> struct nested { static constexpr bool is_spec = false; }; }; Мы можем сделать частичную специализацию класса nested, которая зависит от параметров шаблонного класса str:

Декларативное описание UI на C++20

Несколько лет назад у меня появилась идея как можно реализовать декларативное описание UI на современном C++. Наконец-то нашёл время и реализовал маленькую экспериментальную библиотеку. Ключевая идея заключается в том, что с помощью Class Template Argument Deduction (CTAD), добавленного в C++17, и Variadic Templates, которые существуют ещё с C++11, можно в compile time описывать сложные иерархические структуры данных с помощью фигурных скобок, без явного указания параметров шаблонов. Например, мы можем объявить класс widget для описания виджетов UI следующим образом:

Deducting this в C++23

В C++23 завезут Deducting this. Если коротко, то это возможность указать this как явный параметр метода класса, при этом тип этого параметра может быть шаблоном. Основное применение Deducting this - это устранение дублирующегося кода для одинаковых методов с разными cv-qualifiers (const/volatile) и ref-qualifiers (&, &&). Например у нас есть следующий код на C++ 20, который идиоматически правильно определяет все варианты доступа к одной из своих переменных: class my_class { public: int & data() & { return data_; } const int & data() const & { return data_; } int && data() && { return std::move(data_); } private: int data_; }; С помощью Deducting this мы сможем заменить три одинаковых варианта функции data одним:

Использование C++20 Coroutines для генерации интервалов

Попробовал использовать C++20 coroutines для генерации интервалов. Выглядит всё довольно неплохо. Вот небольшой пример использования. Пусть у нас есть класс, содержащий внутри себя вектор уникальных указателей на векторы целых чисел, и некоторые из этих указателей могут быть null. Надо вернуть из функции класса интервал, содержащий все элементы ненулевых векторов и какую-нибудь заданную последовательность (например 10 единиц) для нулевых векторов: class my_class { public: auto data() const { // ??? } private: std::vector<std::unique_ptr<std::vector<int>>> data_; }; С помощью одной лишь библиотеки ranges эта проблема не имеет простого решения.

Правильные setters на современном C++

В старом добром C++03 были довольно простые правила передачи параметров в функции, поэтому никаких вопросов с написанием сеттеров не возникало. Все объекты должны передаваться по константной ссылке, чтобы избежать лишнего копирования, и этот же подход надо было использовать и в сеттерах. Например, типичный сеттер для std::string выглядел вот так: class my_class { public: void set_name(const std::string & n) { name_ = n; } private: std::string name_; }; Вообще говоря, этот код и раньше вызывал некоторые вопросы.

Агоритмы с довесками в compile-time

Сейчас делал простой класс для кэширования кусков больших данных, полученных из какого-нибудь абстрактного источника данных большого размера. Класс хранит в себе std::map, отображающий смещения в источнике данных в куски закэшированных данных. Хочется, чтобы в классе была функция, которая по смещению и размеру возвращает вектор из регионов, в каждом из которых указан размер и кусок данных, если в этом регионе данные загружены. Что-нибудь типа такого (эффективность из-за копий данных пока оставим в стороне):

Argument-dependent lookup в C++

Как-то со всеми этими новыми модными штучками типа концептов и constexpr стали забываться базовые вещи из C++ и вся та жесть, которая может быть с ними связана. Вот сейчас нарвался на баг, связанный с со старым добрым Argument-dependent lookup, и задумался о том, а как вообще писать безопасный с точки зрения ADL код в библиотеках. Допустим вы реализуете какую-то библиотеку lib1, в которой содержатся шаблонные функции для работы с произвольными определёнными пользователем типами данных.

Ref-qualifiers

Сегодня похоже день каких-то удивительных открытий. Сейчас копался в исходниках ranges в libstdc++ и наткнулся на вот такое объявление функции-члена в классе: void foo() &&. Оказывается, что в C++11 были введены по аналогии с квалификаторами const и volatile квалификаторы rvalue и lvalue references на функции-члены.

Определение тела friend функции внутри класса

Век живи - век учись. Сейчас внезапно для себя обнаружил, что в C++ тело friend-функции можно определять прямо внутри класса:

struct cls {
    friend void foo(cls & c) {
    }
};

// ...

cls c;
foo(c);

User-defined сlass template argument deduction guides в C++17

Недавно внезапно обнаружил для себя user-defined deduction guides для вывода типов параметров шаблонных классов в С++17.