Мой компилятор ведет себя странно, когда я пытаюсь передать массив фиксированного размера в функцию шаблона. Код выглядит следующим образом:
#include <algorithm>
#include <iostream>
#include <iterator>
template <typename TSize, TSize N>
void f(TSize (& array)[N]) {
std::copy(array, array + N, std::ostream_iterator<TSize>(std::cout, " "));
std::cout << std::endl;
}
int main() {
int x[] = { 1, 2, 3, 4, 5 };
unsigned int y[] = { 1, 2, 3, 4, 5 };
f(x);
f(y); //line 15 (see the error message)
}
Он производит следующую компиляцию в GCC 4.1.2:
test.cpp|15| error: size of array has non-integral type ‘TSize’ test.cpp|15| error: invalid initialization of reference of type ‘unsigned int (&)[1]’ from expression of type ‘unsigned int [5]’ test.cpp|6| error: in passing argument 1 of ‘void f(TSize (&)[N]) [with TSize = unsigned int, TSize N = ((TSize)5)]’
Обратите внимание, что первый вызов компилируется и выполняется успешно. Это, по-видимому, означает, что хотя int
является интегралом, unsigned int
не является.
Однако, если я изменю объявление моего вышеописанного шаблона функции на
template <typename TSize, unsigned int N>
void f(TSize (& array)[N])
проблема просто уходит! Обратите внимание, что единственное изменение здесь - от TSize N
до unsigned int N
.
Раздел [dcl.type.simple
] в окончательном проекте ISO/IEC FDIS 14882: 1998, по-видимому, подразумевает, что "интегральный тип" либо подписан, либо без знака:
Спецификатор
signed
заставляетchar
объекты и битовые поля подписать; он избыточен с другими интегральными типами.
Что касается объявлений массивов фиксированного размера, проект говорит [ dcl.array
]:
Если присутствует константное выражение (
expr.const
), оно должно быть интегральным постоянным выражением и его значение должно быть больше нуля.
Итак, почему мой код работает с явным типом размера unsigned
с типом inferred signed
, но не с типом типа unsigned
?
EDIT Серж хочет знать, где мне понадобится первая версия. Во-первых, этот пример кода, очевидно, упрощен. Мой реальный код немного более сложный. Массив на самом деле представляет собой массив индексов/смещений в другом массиве. Итак, логически, тип массива должен быть таким же, как и его тип размера, для максимальной корректности. В противном случае я могу получить несоответствие типа (например, между unsigned int
и std::size_t
). По общему признанию, это не должно быть проблемой на практике, поскольку компилятор неявно преобразуется в больший из двух типов.
РЕДАКТИРОВАТЬ 2 Я стою исправлено (спасибо, litb): размер и смещение, конечно, логически разные типы, а смещения в массивах C, в частности, имеют тип std::ptrdiff_t
.