cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
91 stars 0 forks source link

Новая семантика ... , частичные CTAD, неименованные локалы и т.д. #565

Open kelbon opened 1 year ago

kelbon commented 1 year ago

Увидел пропозал в С++26 на auto _ которое бы заменялось на [[maybe_unused]] auto x и сгорело немного

Кажется существуют способы гораздо лучше с точки зрения языка, которые решают сразу несколько проблем, моё предложение решает проблемы:

Итак, первая часть пропозала:

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 Пример:

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>;  // использованы два неименованных пака, разных
apolukhin commented 8 months ago

Первую часть скоро примут в стандарт в https://wg21.link/P1061

Вторая часть весьма противоречива и требует прототипа. Если напишите - будет круто, а без него - идея обречена на провал

kelbon commented 8 months ago

Первую часть скоро примут в стандарт в https://wg21.link/P1061

Вторая часть весьма противоречива и требует прототипа. Если напишите - будет круто, а без него - идея обречена на провал

отлично, хорошо что ещё добавили для index_sequence раскрытие, (тут я об этом не писал, но в других местах при обсуждении этой фичи упоминал не раз) А где посмотреть на статус, как определить, что "скоро примут"?)

DaMilyutin commented 3 months ago
// это можно также использовать для создания неименованных переменных
// std::get для lock_guard возвращает *this чтобы это было возможно
auto [...] = std::lock_guard(mtx);
// std::scoped_lock это буквально логический тупл локов
auto [...] = std::scoped_lock(mtxs...);

Возникло сомнение. Такой синтакс может нежелательно распаковать то, что не хотелось бы распаковать? Например, если в правой части возвращается некая структура.