gcc.gnu.org/bugzilla/show_bug.cgi?id=38950

омпилятор ведет себя странно, когда я пытаюсь передать массив фиксированного размера в функцию шаблона. Код выглядит следующим образом:

#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 тип размера, с выводомsigned тип размера, но не с выводомunsigned тип размера?

РЕДАКТИРОВАТЬ Серж хочет знать, где мне нужна первая версия. Во-первых, этот пример кода явно упрощен. Мой настоящий код немного сложнее. Массив на самом деле является массивом индексов / смещений в другом массиве.Таким образом, по логике, тип массива должен быть таким же, как его тип размера для максимальной корректности. В противном случае я могу получить несоответствие типов (например, междуunsigned int а такжеstd::size_t). По общему признанию, это не должно быть проблемой на практике, так как компилятор неявно преобразует в больший из двух типов.

РЕДАКТИРОВАТЬ 2 Я исправлен (спасибо, горит): размер и смещение, конечно, логически разные типы, и смещения в C-массивах, в частности, имеют типstd::ptrdiff_t.

 Serge23 янв. 2009 г., 12:08
Можете ли вы привести пример, когда вам абсолютно необходимо использовать эту первую версию?
 Johannes Schaub - litb23 янв. 2009 г., 12:52
это определенно интересный конрад. Comeau принимает этот код, по крайней мере.
 Serge23 янв. 2009 г., 12:07
Первый пример прекрасно компилируется с помощью компилятора Microsoft (2005). Digital Mars жалуется на «Ошибка: ожидается целочисленное выражение» в строке «void f (TSize (& array) [N]) {»
 Ismael23 янв. 2009 г., 12:50
В теме о деструкторе базовых типов было подтверждено, что вы не можете вызвать ~ int напрямую, но внутри шаблона делаете typedef int MyType; вызов ~ MyType был законным. Но я думаю, что правильный подход - использовать size_t для второго параметра.
 Konrad Rudolph23 янв. 2009 г., 13:06
Серж, Литб, пожалуйста, сделай свои комментарии в ответах, чтобы другие люди могли найти их быстрее (так как я думаю, что они актуальны). @xhantt: я не уверен, что деструктор имеет к этому отношение. Нигде в моей функции не должен конструктор дляTSize называться (даже неявно).

Ответы на вопрос(1)

Решение Вопроса

14.8.2.4 / 15:

Если в объявлении шаблона функции с нетиповым шаблоном-параметром нетипичный шаблон-параметр используется в выражении в списке параметров функции и, если выводится соответствующий аргумент шаблона, то тип аргумента должен точно соответствовать типу шаблона-параметра,за исключением того, что аргумент шаблона, выведенный из границы массива, может иметь любой целочисленный тип.

Предоставление этого примера:

template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
    A<1> a;
    f(a);    // error: deduction fails for conversion from int to short
    f<1>(a); // OK
}

Это говорит о том, что компиляторы, которые не могут скомпилировать ваш код (очевидно, GCC и Digital Mars), делают это неправильно. Я протестировал код с Comeau, и он прекрасно компилирует ваш код. Я не думаю, что есть разница в том, зависит ли тип параметра шаблона нетипичного типа от параметра типа или нет.14.8.2.4/2 говорит, что аргументы шаблона должны быть выведены независимо друг от друга, а затем объединены в тип функции-параметра. В сочетании с / 15, который позволяет типу измерения быть другого целочисленного типа, я думаю, что ваш код в порядке. Как всегда, я беру карту C ++ - это сложно, поэтому я могу ошибаться :)

ОбновитьЯ изучил отрывок в GCC, где он выдает это сообщение об ошибке:

  ...
  type = TREE_TYPE (size);
  /* The array bound must be an integer type.  */
  if (!dependent_type_p (type) && !INTEGRAL_TYPE_P (type))
    {
      if (name)
    error ("size of array %qD has non-integral type %qT", name, type);
      else
    error ("size of array has non-integral type %qT", type);
      size = integer_one_node;
      type = TREE_TYPE (size);
    }
  ...

Кажется, что было пропущено, чтобы пометить тип размера как зависимый в более раннем кодовом блоке. Поскольку этот тип является параметром шаблона, он является зависимым типом (см.14.6.2.1).

Обновить: Разработчики GCC исправили это:Ошибка № 38950

 Konrad Rudolph23 янв. 2009 г., 15:20
Я думаю, что вы, вероятно, правы. Спасибо за поиск соответствующего отрывка.
 Konrad Rudolph23 янв. 2009 г., 21:58
litb, вы подали отчет об ошибке или представили патч? Это, вероятно, должно быть сделано. Я свободно признаю, что я запуган проектом Кракен GCC и не знаю, как это сделать.
 Johannes Schaub - litb23 янв. 2009 г., 22:04
Конрад Рудольф, я думал, что оставлю работу для вас, чтобы вы могли заработать славу, но если у вас нет времени или вы не хотите это делать, я сделаю это. Просто оставьте еще один комментарий в этом случае.
 Johannes Schaub - litb23 янв. 2009 г., 22:14
Похоже, это связано:gcc.gnu.org/bugzilla/show_bug.cgi?id=33553
 Johannes Schaub - litb23 янв. 2009 г., 22:40
я сообщил об этом:gcc.gnu.org/bugzilla/show_bug.cgi?id=38950

Ваш ответ на вопрос