Недавно я написал шаблон функции, который ссылается на C-массив:
template <class T, size_t N>
void foo(T(&c_array)[N]);
Предполагая, что T является char
, длина C-строки равна N - 1
из-за нулевого терминатора. Я понял, что я должен, вероятно, обработать краевой регистр, где N == 0
, потому что тогда N - 1
будет std::numeric_limits<std::size_t>::max()
.
Итак, чтобы избежать хаоса, который может возникнуть в редком случае, когда кто-то передает массив нулевой длины этой функции, я поставил чек на N == 0
.
Однако, к моему удивлению, кажется, что массив нулевой длины фактически не является даже типом массива - или, по крайней мере, тем, что, по-видимому, считает GCC. Фактически, массив нулевой длины даже не связывается с указанной сигнатурой функции, если в качестве кандидата доступна функция с сигнатурой типа указателя.
Рассмотрим следующий код:
template <class T, size_t N>
void foo(T(&array)[N])
{
std::cout << "Array" << std::endl;
}
void foo(const void* p)
{
std::cout << "Pointer" << std::endl;
}
int main(int argc, char** argv)
{
char array1[10] = { };
const char* pointer = 0;
char array2[0] = { };
foo(array1);
foo(pointer);
foo(array2);
}
С GCC 4.3.2 это выдает:
Array
Pointer
Pointer
Как ни странно, массив нулевой длины предпочитает связываться с функцией, которая принимает тип указателя. Итак, является ли это ошибкой в GCC или существует какая-то неясная причина, установленная стандартом С++, почему это поведение необходимо?