Возможность использовать auto в качестве типового параметра другого типа
evilenzo opened this issue · 1 comments
Описание
На данный момент если мы хотим иметь какой-то констрейнт для шаблонного типа, мы пишем что-то в таком духе:
template <typename T>
void foo(std::optional<T> opt_arg);
Это полезно и для пользователя, т.к. в объявлении он явно видит, что аргумент, например, обёрнут optional'ом, и для разработчика, т.к. он получает автокомплит от IDE.
Но есть и несколько минусов, например, излишняя вербозность, в особенности, когда имя типа больше использоваться не будет.
С 20-м стандартом появилась возможность переписать код подобным образом:
template<typename T>
struct is_optional : std::false_type {};
template <typename T>
struct is_optional<std::optional<T>> : std::true_type {};
template <typename T>
concept Optional = is_optional<T>::value;
/* В некоторых случаях можно сделать так:
template <typename T>
concept Optional = std::is_same_v<std::optional<T::value_type>, T>;
*/
void foo(Optional auto opt_arg);
Но вербозность это не особо уменьшает и всё ещё имеет множество минусов, например, нужда реализовывать такие констрейнты под каждый тип.
Чтобы решить проблему, предлагается такая запись:
void foo(std::optional<auto> opt_arg);
Либо, как вариант, вообще самостоятельно не писать шаблонные параметры и разрешить такую запись:
void foo(std::optional opt_arg);
Мотивация
Как было сказано выше, уменьшить вербозность, не писать лишний код, когда нам неинтересен сам тип, при этом иметь автокомплит и полезную информацию для пользователя.
Сложности
Нужно решить вопрос с несколькими параметрами у типа. Пример:
template <typename A, typename B>
struct TwoParams {};
// Вариант 1
void foo(TwoParams<auto, auto> arg);
// Вариант 2
void foo(TwoParams<auto> arg);
// Вариант 3
void foo(TwoParams<auto...> arg);
В случае с третьим вариантом есть вопросы по другим нюансам, например, когда таких аргументов несколько.
Полезные ссылки:
- https://quick-bench.com/ - онлайн бенчмарк, поможет вам продемонстрировать эффективность вашего подхода
- https://godbolt.org/ - онлайн дизассемблер
- https://eel.is/c++draft/ - черновик стандарта C++ с возможностью ссылаться на конкретные параграфы
- https://wg21.link/ - универсальная ссылка на международные proposal или баги в С++, например https://wg21.link/P1000 ссылается на документ P1000, а https://wg21.link/cwg100 на 100 баг в ядре языка
Варианты 2 и 3 кажутся нелогичными/неправильными, а 1 даже уже работает в GCC но с некоторыми ограничениями (https://gcc.godbolt.org/z/6xGTPo49h):
template <typename A, typename B>
struct TwoParams {};
void foo(TwoParams<auto, auto> arg);
void test() {
foo(TwoParams<int, int>());
foo(TwoParams<short, long>());
}
void bar(void(*)(auto)); // not ok
template<typename T>
using FPtr = void(*)(T);
void baz(FPtr<auto>); // ok
На примере bar
видно, что есть некоторые проблемы в том, чтобы заходя "вглубь" типа понимать, auto
это неявный шаблонный параметр внешней функции, или что-то другое.