Новая семантика ... , частичные CTAD, неименованные локалы и т.д.
Увидел пропозал в С++26 на auto _ которое бы заменялось на [[maybe_unused]] auto x и сгорело немного
Кажется существуют способы гораздо лучше с точки зрения языка, которые решают сразу несколько проблем, моё предложение решает проблемы:
- множества make* функций
- неименованных локалов(которые хочется не именовать)
- structured binding и рефлексия на его основе
- более удобное метапрограммирование и новые возможности в нём(понятные и логичные)
- решение проблемы "как написать универсальное is_specialization_of"
- и т.д.
Итак, первая часть пропозала:
auto [...args] = x; // структурная привязка в вариадик
auto [a, b, ...args] = x; // два первых аргумента обычные, остальные вариадик
auto [a, ...] = x; // первый аргумент обычный, остальные НЕИМЕНОВАННЫЙ вариадик
auto [..., a] = x; // выделение последнего и неименованный вариадик в начале
auto [a, ..., b] = x; // и даже так, если tuple_size_v < 2, то программа ill formed
// это можно также использовать для создания неименованных переменных
// std::get для lock_guard возвращает *this чтобы это было возможно
auto [...] = std::lock_guard(mtx);
// std::scoped_lock это буквально логический тупл локов
auto [...] = std::scoped_lock(mtxs...);
Вторая часть пропозала:
В контексте декларации шаблонных аргументов ... X будет означать пак любых аргуменов, например здесь Args это пак ЛЮБЫХ аргументов, не только типов
template<... Args>
Это позволяет сделать следующее
template<typename>
struct is_specialization : std::false_type {};
template<...Args, template<...> typename Template>
struct is_specialization<Template<Args...>> : std::true_type {};
Контекст декларации аргументов функции
// это шаблон функции с неименованным паком аргументов аналогично тому как работает void foo(auto);
void foo(vector<int, ...>);
// эквивалентно этому переписанному коду(если бы были аргументы не типы у шаблона, то добавило бы их тоже)
template<typename... Args>
void foo(vector<int, Args...>)
// Аналогично для
void foo(vector<...>); // неименованный пак
void foo(vector<... Args>); // именованный пак
template<typename Alloc>
void foo(vector<int, Alloc, ...>); // тоже работает, сейчас на гцц такое поведение поддержано
void foo(vector<..., int, ...>); // ошибка компиляции
void foo(vector<...> v, unique_ptr<...>); // работает
Контекст передачи шаблонных шаблонных аргументов Template<Type, ...> - алиас на Template с requires что первый тип same_as<Type> Пример:
view | to<vector<int, ...>> // переписывается в то что ниже
template<same_as<int> T, ... Args> // all args, not just types
using __alias_vector = vector<T, Args...>;
view | to<vector<int, ...>>
Контекст вывода типов переменных (CTAD)
// применяет частичный CTAD с переданным пользователем типом int
vector<int, ...> x = vector<float, myaloc>();
// выполняет полный CTAD
vector<...> x = vector<int>();
Механизм работы частичного CTAD: У компилятора имеются дедакт гайды, в некоторых из них типы СПРАВА undeductible, в этом случае это называется частичный дедакт гайд(сейчас это запрещено) При передаче пользователем части аргументов компилятор подставляет их и некоторые из частичных дедакт гайдов становятся полными, после этого компилятор делает обычный CTAD как сейчас(это похоже на C++20 фичу с дедакт гайдом из алиасов, просто фактически как и выше Template<Args, ...> создаёт алиас по которому компилятор выводит полный тип)
Пример:
// это частичный дедакт гайд
// компилятор видит что тип U в типе справа невыводим, но когда пользователь сам передаёт тип U
// компилятор имеет всю информацию чтобы вывести тип
template<typename T, typename U, typename Alloc>
vector(vector<T, Alloc>) -> vector<U, Alloc>;
// использование. Компилятор видит слева int, подставляет в дедакт гайд,
// остаётся вывести аллокатор, дедакт гайд подсказывает, что он my_alloc
vector<int, ...> v = vector<float, my_alloc>{};
Этот частичный дедакт гайд также можно переписать с помощью пропозала короче
template<typename Alloc>
vector(vector<..., Alloc>) -> vector<..., Alloc>; // использованы два неименованных пака, разных
Первую часть скоро примут в стандарт в https://wg21.link/P1061
Вторая часть весьма противоречива и требует прототипа. Если напишите - будет круто, а без него - идея обречена на провал
Первую часть скоро примут в стандарт в https://wg21.link/P1061
Вторая часть весьма противоречива и требует прототипа. Если напишите - будет круто, а без него - идея обречена на провал
отлично, хорошо что ещё добавили для index_sequence раскрытие, (тут я об этом не писал, но в других местах при обсуждении этой фичи упоминал не раз) А где посмотреть на статус, как определить, что "скоро примут"?)
// это можно также использовать для создания неименованных переменных
// std::get для lock_guard возвращает *this чтобы это было возможно
auto [...] = std::lock_guard(mtx);
// std::scoped_lock это буквально логический тупл локов
auto [...] = std::scoped_lock(mtxs...);
Возникло сомнение. Такой синтакс может нежелательно распаковать то, что не хотелось бы распаковать? Например, если в правой части возвращается некая структура.