Используется метод, в котором длина массива является аргументом шаблона, то есть:
template< typename T, size_t L >
void foo( T (&arr)[L] )
{
}
Поскольку строковый литерал имеет известную длину L, его можно вывести, например, foo ("test"), являющийся foo (). Могу поспорить, что есть перегрузка для const char *, где предполагается, что аргумент является c-строкой, где strlen () может использоваться для определения длины.
РЕДАКТИРОВАТЬ: Лучшее объяснение того, как ifind_first потерпит неудачу и почему не будет, если вы будете осторожны
Что решит, будет ли ifind_first провален или нет в этом случае, так это то, превратится ли тема или поиск в символ *. В этом случае вы передали строковый литерал в качестве непосредственного поиска, ifind_first попытается и предположит, что это const char [10] (длина "substring" + 1 для терминатора NULL). Однако для поиска это не имеет значения, потому что даже если он выродится в const char *, ifind_first будет догадываться, что это строка c с нулевым символом в конце, а строковый литерал является строкой c с нулевым символом в конце, поэтому он работает.
В этом случае вы действительно запрашиваете буфер символов [1024], в вашем случае он не вырождается в символ *. Но если бы вместо этого у вас было бы, скажем, char * buffer = new char [1024]; тип буфера - char *, и он не гарантированно завершается NULL. В этом случае ifind_first завершится сбоем таинственным образом, в зависимости от того, что находится после заполненной области.
Итак, в заключение, поскольку тип буфера char [1024], в вашем случае он не будет касаться памяти за концом буфера, НО, он также не будет заботиться о том, есть ли в нем терминатор NULL (он не не ищите его, поскольку вы передали ему символ [1024], который знает длину во время компиляции). Так что, если, скажем, вы заполнили буфер 12 символами, за которыми следует NULL, он все равно будет искать весь буфер.