Daily bit(e) C++. Паттерн «Странно рекурсивный шаблон»

Добавлено 16 сентября 2023 в 23:39

Daily bit(e) C++ #218, метод в C++ для передачи информации о типе производного класса в базовый класс: паттерн «Странно рекурсивный шаблон».

Daily bit(e) C++

Паттерн «Странно рекурсивный шаблон» (Curiously Recurring Template Pattern, CRTP) – это метод в C++, позволяющий нам передавать информацию о типе производного класса в базовый класс.

Типичным вариантом использования CRTP является поддержка Mixin, при которой мы инкапсулируем функциональность в базовый класс, не полагаясь на виртуальную диспетчеризацию. Таким образом, производный класс может избежать полиморфизма и потенциально оставаться легко копируемым.

#include <span>
#include <vector>

struct Connection{};
struct ServerConfig{};

// Тип Base/Mixin
template <typename Handler>
struct SimpleServer 
{
    // Открытый интерфейс, предоставляемый через производный класс.
    void listen() 
    {
        bool running = true;
        while (running) 
        {
            Connection conn = accept_connection();
            // Безопасно, потому что мы знаем,
            // что Handler — это производный класс.
            static_cast<Handler*>(this)->handle_connection(conn);
        }
    }
protected:
    // Защищенный интерфейс, используемый только производным классом.
    int read(Connection, std::span<std::byte>) { /* реализация */ }
    int write(Connection, std::span<std::byte>) { /* реализация */ }
    // Предотвращение случайного прямого создания экземпляра
    SimpleServer(ServerConfig cfg) { /* реализация */ }
private:
    Connection accept_connection() { /* реализация */ }
};

// Пользователям нужно только инициализировать и реализовать метод handle.
struct ServerImpl : SimpleServer<ServerImpl> 
{
    ServerImpl() : SimpleServer<ServerImpl>(ServerConfig{}) {}

    void handle_connection(Connection conn) 
    {
        std::vector<std::byte> buff(64*1024);
       // SimpleServer<SererImpl>::read()
        int rres = read(conn, buff);
      
        /* обработка данных */
      
        // SimpleServer<SererImpl>::write()
        int wres = write(conn, buff);
    }
};

int main() 
{
    ServerImpl server;
    server.listen();
}

Открыть пример на Compiler Explorer.

Теги

C++ / CppDaily bit(e) C++Паттерны проектирования / Design PatternsПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.