Closed infy-infy closed 2 years ago
Интересное предложение. Оно может сработаться в группе с propconst
[P1974]
Он предлагался еще в 2015-2016, и возродился в 2020, у него юзкейс таков, что без него не заработает non-transient память из constexpr.
propconst
это квалификатор для указательных/ссылочных типов:
T propconst*
T propconst&
Если T
константный, то он конвертируется в const
, иначе просто пропадает
int propconst * ---> int *
int propconst * const ---> int const * const
Если это предложение примут, то будет дублирование и два get
вместо одного
template <typename T>
struct unique_ptr
{
T* get(); // Resolves to U* if T is propconst U
T* const get() const; // Resolves to const U* if T is propconst U
};
Надо сделать так, чтобы был один, с declqual
В грядущем стандарте уже приняли deducing this
- новый синтаксис определения метода, который покрывает ваш юзкейс
Приняли в стандарт C++23 https://wg21.link/P0847
declqual(T)
должен "возвращать" квалификаторы, принимая на вход тип. Рассмотрим механику работы на следующем примере:В данном случае, если T не является ссылкой или является lvalue ссылкой, то квалификатор метода будет
&
. Если T это константная ссылка (строго говоря, типconst T&
илиconst T&&
это ссылка на константный тип, но все привыкли говорить "константная ссылка"), то квалификаторы будут, соответственно,const &
илиconst &&.
Если T это rvalue ссылка, то квалификатор будет&&
.declqual(auto)
будет создавать все варианты квалификаторов по мере того, как компилятор будет натыкаться на очередной вариант использования. На самом деле, юзкейс этого выражения и является основным мотиватором этой идеи: с помощью этого выражения можно будет избавиться от дублирования кода или использования уродливого const_cast в геттерах. Например:Раньше:
Стало
Как можно заметить, в последнем примере стоит
&
после выражения: я предлагаю оставлять возможность сокращать количество вариаций за счет явного указания квалификаторов после выражениеdeclqual
. В примере выше это означает, чтоget_by_key
может иметь квалификаторы толькоconst&
или&
(ну и формально, конечно, варианты сvolatile
). Явное указание может производится либо непосредственной подстановкой руками, либо с помощью того жеdeclqual
. Например:В данном случае второй declqual говорит о том, что ссылочный квалификатор get() может быть либо && (если T - это rvalue ссылка), либо & (когда тип lvalue ссылка или не ссылка). Поэтому declqual(auto) может варьировать только cv квалификаторы для конкретного класса.
объявление
T get() declqual(auto) const volatile &
не должно считаться ошибкой, т.к. в такое может "вычислиться" declqual(...) в шаблонном коде. Тогда declqual(auto) тут не будет иметь никакого эффекта, т.к. все квалификаторы указаны явно.Однако этого может оказаться недостаточно, если мы хотим явно запрещать cv квалификаторы. По аналогии с consteval предлагаю ввести подобную запись:
T get() declqual(auto) !volatile &
- это означает, что варьироваться может только const квалификатор, а volatile всегда отсутствует. Разумеется, разрешить подобное только при использовании declqual(auto), чтобы нельзя было обычные методы помечать как !const или !volatile.Я вижу данный инструментарий логичным продолжением функциональности explicit(bool), которая убивает сразу двух зайцев - во-первых, дает возможность управлять квалификаторами методов из шаблонного кода, во-вторых - избавляет язык от проблемы геттеров. Однако нужно придумать более мощные примеры полезного использования declqual(T), текущие демонстрируют только принцип работы.