scl-utility

Forward-like типажи

Это набор вспомогательных инструментов (типажей) для работы с типами в C++.

Они позволяют “пробрасывать” (копировать) квалификаторы типа, такие как const, volatile и тип ссылки (& или &&), от одного типа объекта к другому.

Содержание:


forward_like_t<Base, Type>

Создаёт новый тип, применяя к Type cv/ref-семантику из Base в соответствии с правилами C++23 std::forward_like.

Данный типаж модифицирует Type путём наложения const/volatile квалификаторов из Base (сохраняя собственные квалификаторы Type) и полной замены ссылочной категории Type на категорию из Base.

Семантика

Примеры

#include <scl/utility/type_traits.h>

using ::scl::forward_like_t;

// CV-квалификаторы добавляются (объединяются); не-ссылочный Base → rvalue-ссылка
static_assert(std::is_same_v<forward_like_t<const int, double>, const double &&>);
static_assert(std::is_same_v<forward_like_t<const int, volatile double>, const volatile double &&>);
static_assert(std::is_same_v<forward_like_t<int, const double>, const double &&>);

// Ссылочная категория заменяется (копируется из Base)
static_assert(std::is_same_v<forward_like_t<int&, double&&>, double&>);   // && у double заменяется на &
static_assert(std::is_same_v<forward_like_t<int&&, double&>, double&&>);  // & у double заменяется на &&
static_assert(std::is_same_v<forward_like_t<int, double&>, double &&>);   // не-ссылочный Base → &&

// Гибридное поведение
static_assert(std::is_same_v<forward_like_t<const int&, volatile double&&>, const volatile double&>);

// Особый случай для void
static_assert(std::is_same_v<forward_like_t<const int&, void>, const void>);
static_assert(std::is_same_v<forward_like_t<int&&, const void>, const void>); // Ссылка не применяется к void

// Массивы
static_assert(std::is_same_v<forward_like_t<const int, int volatile[3]>, int const volatile (&&)[3]>);
static_assert(std::is_same_v<forward_like_t<int&, int[3]>, int (&)[3]>);
static_assert(std::is_same_v<forward_like_t<int&&, int const(&)[3]>, int const (&&)[3]>);

Типичные применения

Используется для точного воспроизведения поведения std::forward_like из C++23, обеспечивая консистентную логику передачи аргументов в разных версиях стандарта C++. Полезен, когда квалификаторы типа-обёртки Base должны быть применены к передаваемому значению Type.

См. также


forward_like<Base, T>(t)

Вспомогательная функция, которая передаёт значение t как ссылку с cv/ref-квалификаторами, определёнными с помощью forward_like_t. Является прямым аналогом std::forward_like из C++23.

Описание

Эта функция выполняет static_cast на входном значении t к типу, полученному из forward_like_t<Base, T&&>. Она идеально передаёт значение с желаемыми cv/ref-свойствами, делая обобщённый код чище и выразительнее.

Пример

#include <scl/utility/type_traits.h>
#include <iostream>
#include <string>

// Функция, обрабатывающая строку, с поведением, зависящим от квалификаторов
void process(const std::string& str) { std::cout << "Обработка const lvalue-ссылки: " << str << std::endl; }
void process(std::string& str)       { std::cout << "Обработка non-const lvalue-ссылки: " << str << std::endl; }
void process(std::string&& str)      { std::cout << "Обработка rvalue-ссылки: " << str << std::endl; }

// Обобщённая обёртка, которая передаёт свой аргумент "подобно" параметру T
template <typename T, typename U>
void wrapper(U&& arg)
{
    // Передаём arg с квалификаторами из T
    process(scl::forward_like<T>(arg));
}

int main()
{
    std::string s = "привет";
    const std::string cs = "мир";

    wrapper<const int&>(s); // Передаём s как const lvalue-ссылку
    wrapper<int&>(s);       // Передаём s как non-const lvalue-ссылку
    wrapper<int&&>(std::move(s)); // Передаём временный объект как rvalue-ссылку
    // wrapper<int&>(cs);      // Ошибка компиляции
}

Последняя закомментированная строка в main не скомпилируется, потому что forward_like_t<int&, const std::string&> даёт тип const std::string&. У функции process нет перегрузки, которая могла бы связать const std::string& с параметром std::string&. Это демонстрирует, как forward_like корректно сохраняет const-квалификатор от базового типа значения.