Почему C не может определить размер массива со смещением?

#c

Вопрос:

Этот код не удается скомпилировать

 template<unsigned n>
void test(char const (*)[n   1]) { }

int main()
{
    char const arr[] = "Hi";
    test(amp;arr);
}
 

с ошибкой

 note: candidate template ignored: couldn't infer template argument 'n'
 

Однако, если вы измените n 1 на n , он будет отлично компилироваться.

Почему компилятор не может сделать вывод n , если к нему добавлено смещение?

Комментарии:

1. Но чего именно вы пытаетесь достичь, я не понимаю? Я имею в виду, что правила для совместимых типов требуют, чтобы размеры массива совпадали один к одному.

2. Как насчет мысленного упражнения? Что , если бы шаблон был указан как void test(char const (*)[(n 3)*(n-2)]) , вы ожидали бы, что компилятор C выведет n значение 9 при передаче массива из 84 символов?

3. @SamVarshavchik: Нет, но это не значит, что он не мог справиться с базовым аффинным выражением.

Ответ №1:

Из ссылки cpp в разделе «Не выведенные контексты» :

В следующих случаях типы, шаблоны и значения, не относящиеся к типу, которые используются для создания P, не участвуют в выводе аргументов шаблона, а вместо этого используют аргументы шаблона, которые были выведены в другом месте или явно указаны. Если параметр шаблона используется только в не выводимых контекстах и явно не указан, вывод аргумента шаблона завершается ошибкой.

(…)

  1. Аргумент шаблона, не относящийся к типу, или массив, связанный, в котором подвыражение ссылается на параметр шаблона:
 template<std::size_t N> void f(std::array<int, 2 * N> a);
std::array<int, 10> a;
f(a); // P = std::array<int, 2 * N>, A = std::array<int, 10>:
      // 2 * N is non-deduced context, N cannot be deduced
      // note: f(std::array<int, N> a) would be able to deduce N 
 

(…)

В любом случае, если какая-либо часть имени типа не выводится, все имя типа не выводится из контекста. (…)

Поскольку n 1 это подвыражение, весь контекст тогда не может быть выведен.

Комментарии:

1. 1 спасибо. Но знаете ли вы (n) , должно ли это сработать тогда? Потому что он не работает на Clang, но работает на GCC и MSVC.

2. @user541686 Я думаю, что Лязг прав. (n) следует сделать n подвыражение, которое должно сделать все это не выводимым контекстом. Это то, что также говорится в сообщении об ошибке Clang: «не удалось вывести аргумент шаблона …»