Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Возможность использовать auto в качестве типового параметра другого типа #577

Open
evilenzo opened this issue Sep 10, 2023 · 1 comment

Comments

@evilenzo
Copy link

Описание

На данный момент если мы хотим иметь какой-то констрейнт для шаблонного типа, мы пишем что-то в таком духе:

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 баг в ядре языка
@AndreyG
Copy link

AndreyG commented Sep 13, 2023

Варианты 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 это неявный шаблонный параметр внешней функции, или что-то другое.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants