Если коротко,
правила автоматического вывода шаблонных аргументов предусматривают вывод полного типа для переданного аргумента при инстанцировании шаблона функции.
Что это означает на практике? В языке есть термин
массива статического размера. Частным примером такого массива является
строковой литерал. Конкретно у строкового литерала из простых символов тип будет таким:
const char[N]
, где
N
- это размер памяти под строковой лиерал, в байтах.
Таким образом, если сделать такое объявление шаблона
template< typename TValue >
void Foo( TValue& value ); // (1)
то при инстанцировании как
Foo( "Hello" );
аргумент
TValue
определится как
const char[6]
.
И мы довольно легко можем воспользоваться этим механизмом. Нужно только дать пояснение, как и во что стоит выводить шаблонные аргументы.
Шаблон можно записать вот так:
template< typename TValue, size_t LENGTH >
void Foo( TValue (&value)[ LENGTH ] ); // (2)
В этом случае при инстанцировании как
Foo( "Hello" );
, аргумент
TValue
будет выведен как
const char
, а нетиповой аргумент
LENGTH
будет выведен в значение
6
.
Собственно, все. Размер переданного массива получен.
Такой шаблон считается более специализированным по отношению к определению выше. Поэтому при наличии обоих шаблонов, инстанцирование для прочих типов будет выбирать первый шаблон, а инстанцирование для массивов статического размера будет проваливаться во второй, как в более специализированный.
В чем суть модификаторов в параметрах шаблона
Если первый шаблон объявить как
template< typename TValue >
void Foo( TValue value );
то инстанцирование произойдет не для типа массива статического размера, а для указателя на первый элемент этого массива. Это произойдет из-за неявного приведения. Стандарт явно пишет что массив статического размера по значению не передается.
Ссылка позволяет избежать приведения. И опять же, сам массив в функцию передан не будет, только ссылка.
И именно поэтому во втором шаблоне тоже используется ссылка.
ибо вызывать функцию, которая определяет размер массива я собираюсь из другой функции, которая так же шаблонная и принимает массив (условно)неизвестного типа данных.
Параметр такой "другой" функции лучше всего определить
универсальной ссылкой и использовать
идеальную передачу. Тогда все будет работать правильно.