Возможно ли автоматическое определение размера псевдонима массива?
Я считаю, что это должно быть возможно при реализации, соответствующей стандарту. Вам не нужно (и нельзя) добавлять дополнительные направляющие.
Однако GCC реализует другой набор правил., чем указано в стандарте:
This implementation differs from [the specification] in two significant ways:
1) We include all template parameters of A, not just some.
2) The added constraint is same_type instead of deducible.
Разработчик полагал, что это упрощение должно иметь такой же эффект для реального использования. Но очевидно, что это не так: эта реализация не работает в вашем случае и ICE в некоторых других случаях.
Для справки я постараюсь следовать стандарту и покажу, как создается руководство для mytype
.
У нас есть это объявление шаблона псевдонима (в стандарте этот шаблон псевдонима называется A
):
template <size_t N>
using mytype = std::array<int, N>;
и это руководство по выводам из стандартной библиотеки ([array.cons]):
template<class T, class... U>
array(T, U...) -> array<T, 1 + sizeof...(U)>;
Сначала шаблон функции (в стандарте называется f
) создается из руководства по дедукции ([over.match.class.deduct] / 1):
template<class T, class... U>
auto f(T, U...) -> array<T, 1 + sizeof...(U)>;
Затем, согласно [over.match.class.deduct] / 2:
аргументы шаблона возвращаемого типа f
выводятся из defining-type-id A
в соответствии с процессом в [temp.deduct.type], за исключением того, что вывод не завершится неудачно, если не все выводятся аргументы шаблона.
То есть мы выводим аргументы шаблона в array<T, 1 + sizeof...(U)>
из std::array<int, N>
. В этом процессе T
выводится как int
; U
не выводится, поэтому остается как есть.
Результат вычитания подставляется в шаблон функции, в результате чего:
template<class T, class... U>
auto g(int, U...) -> array<int, 1 + sizeof...(U)>;
Затем мы генерируем шаблон функции f'
. f'
имеет тот же тип возвращаемого значения и типы параметров функции, что и g
. (Если f
имеет особые свойства, они наследуются f'
.) Но примечательно, что список параметров шаблона f'
состоит из ([over.match.class.deduct] / (2.2), выделено мной):
все параметры шаблона A
(включая их аргументы шаблона по умолчанию) , которые появляются в приведенных выше выводах или (рекурсивно) в их аргументах шаблона по умолчанию, за которыми следуют параметры шаблона f
, которые не были выведены (включая их аргументы шаблона по умолчанию), иначе f'
не является шаблоном функции.
Поскольку N
не появляется в выводе, он не включается в список параметров шаблона (это то, чем GCC отличается от стандартного).
Кроме того, f'
имеет ограничение ([over.match. class.deduct] / (2.3)):
это выполняется тогда и только тогда, когда аргументы A
выводимы (см. ниже) из возвращаемого типа.
Поэтому по стандарту сгенерированный шаблон функции выглядит так:
template<class... U>
requires deducible<array<int, 1 + sizeof...(U)>>
auto f'(int, U...) -> array<int, 1 + sizeof...(U)>;
Очевидно, что в соответствии с этим руководством размер может быть определен как 1 + sizeof...(U)
.
На следующем шаге давайте посмотрим, как определяется deducible
.
[over.match.class.deduct] / 3:
Говорят, что аргументы шаблона A
выводятся из типа T
, если при заданном шаблоне класса
template <typename> class AA;
с одной частичной специализацией, список параметров шаблона которой соответствует A
, а список аргументов шаблона является специализацией A
со списком аргументов шаблона A
([temp.dep.type]), AA<T>
соответствует частичной специализации.
В нашем случае частичная специализация будет:
template <size_t N> class AA<mytype<N>> {};
Итак, deducible
можно объявить как:
template <class T> concept deducible = requires { sizeof(AA<T>); };
Поскольку N
выводится из 1 + sizeof...(U)
, array<int, 1 + sizeof...(U)>
всегда является допустимым совпадением для mytype<N>
(также известного как std::arrray<int, N>
), и, таким образом, ограничение deducible<array<int, 1 + sizeof...(U)>>
всегда выполняется.
Следовательно, согласно стандарту, сгенерированное руководство является жизнеспособным и может определять размер.
Для сравнения, GCC генерирует:
template<class... U, size_t N>
requires same_type<array<int, 1 + sizeof...(U)>, mytype<N>>
auto f_(int, U...) -> array<int, 1 + sizeof...(U)>;
... который не может вывести N
.
person
cpplearner
schedule
21.11.2020