Daily bit(e) C++. Паттерн «Странно рекурсивный шаблон»
Daily bit(e) C++ #218, метод в 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.