Я работал над шаблоном для функции. Для упрощения скажем, что это выглядит так:
template < typename T >
void f(const T & x)
{
cout << "generic case" << endl;
cout << x << endl;
}
Я всегда думал, что C-строки нельзя использовать в качестве аргументов параметров шаблона. Но на самом деле работает следующее (с использованием g ++ 4.5.1):
f("hello world");
Итак, мой вопрос: что T
когда я звоню f("hello world")
?
Я пытался специализироваться, чтобы увидеть, что именно происходит. Например с char[]
является const char*
Я посмотрел на это (что, очевидно, не работает):
template < typename T >
void f(const T & x)
{
cout << "generic case" << endl;
cout << x << endl;
}
template <>
void f(const const char * T & x)
{
cout << "char[] case" << endl;
cout << x << endl;
}
и попробовал несколько вариантов. Никто из них не работает.
В сторону: мне не нужно это для того, что я делаю. Мне нужна специализация для случая T = «C-строка», поэтому я просто написал другую функцию шаблона:
template < typename T >
void f(const T & x)
{
cout << "generic case" << endl;
cout << x << endl;
}
template < typename T >
void f(T x[])
{
cout << "T[] case" << endl;
cout << x << endl;
}
Я просто спрашиваю, потому что мне интересно, что именно происходит и почему C-строка может быть аргументом шаблона, когда то, что я прочитал, говорит, что это не может быть. Я, должно быть, что-то неправильно понял / неправильно понял о шаблонах.
Нет типа C-string. Термин C-строка определяет содержание, а не тип. Он относится к части массива символов, в которой где-то есть нулевой символ, который некоторые функции интерпретируют как конец строки.
Что вас действительно интересует, так это строковый литерал. Строковый литерал имеет тип const char[N]
где N — количество символов в строке, включая неявный нулевой терминатор. Так "hello world"
имеет тип const char[12]
, Вы можете специализироваться на этом так:
template<>
void f(const char(&x)[12])
{
cout << "const char[12] case" << endl;
cout << x << endl;
}
Обратите внимание, что это касается только массивов размера 12. Однако вы можете перегружать (не специализироваться) f()
за все размеры как это:
template<size_t N>
void f(const char(&x)[N])
{
cout << "const char[" << N << "] case" << endl;
cout << x << endl;
}
Также обратите внимание, что эти методы будут также покрывать обычные именованные массивы. Нет никакого способа отличить их от строковых литералов.
Обратите внимание, что это также будет работать как const char [N] и const char *, оба будут выводить,
template < typename T >
void f(const T* x)
{
cout << "const char* case" << endl;
cout << x << endl;
}
Специализация здесь — это постоянный тип указателя.
Если вам нужна специализация на основе типов массивов символов или указателей, вы также можете использовать простую перегрузку функций.