2016-04-16 3 views
4

Следующий код не компилируется:разница между полукоксом [N] и полукоксом (&) [N] в списке параметров

template <int N> 
void f(char[N]) {} 

int main() { 
    char buf[10]; 
    f(buf); 
} 

Если я изменю char[N] к char (&)[N], это работает. Так какая разница между ними?

+1

Первая строка такая же, как 'template void f (char *) {}' after * adjustment *, а затем нет способа вывести 'N' из вызова. Никакая настройка не применяется к 'char (&) [N]', поэтому можно вывести 'N'. –

+0

@ M.M Точно. В тех случаях, когда параметр шаблона не может быть выведен, включая этот, он всегда может явно предоставить его. Ср Мой ответ. –

+0

Почему бы не использовать std :: array в качестве аргумента? –

ответ

2

очевидно, что вы знаете, что char [N] является массивом и char (&)[N] является ссылкой на char [N].

массивы c-style являются специальными при передаче в качестве аргументов по значению. Сам массив не передается, но ссылка есть.

Эти «волшебный» является историческим побочным эффектом С ++ эволюции от С.

передать массив по значению в эти дни мы будем использовать std::array<char, N>, который инкапсулирует массив с стилем.

Обратите внимание, что char (&)[N] рассматривается как буквальный тип и поэтому может быть передан в функции constexpr в контексте constexpr.

+0

* «Сам массив не передается, но ссылка есть». * - ссылка является указателем на первый элемент. – LogicStuff

+0

@LogicStuff, при необходимости, будет разлагаться на указатель, но на самом деле это ссылка на объект и (что важно для вывода шаблона) переносит информацию о типе - включая длину массива. –

+2

«c-style массивы являются специальными при передаче в качестве аргументов по значению»: Да - потому что они просто никогда не бывают. –

6

Вы укусили обратную совместимость с С. При объявлении функции, как:

int f(char c[10]); 

Вы объявляете функцию, аргумент типа char *. Компилятор разбивает тип аргумента для вас. Проблема заключается в том:

int f(char c[5]); 

объявляет же функцию. Это то, как C работал, и C++ сохранил его для совместимости.

int f(char (&c)[10]); 

Объявляет функцию, аргумент которой имеет тип «ссылка на массив (длина 10) символа». C не имеет ссылок, поэтому нет необходимости поддерживать обратную совместимость.

int f(char (&c)[5]); 

Объявляет другую функцию - с другим типом аргумента.

+0

Само по себе ваше объяснение не доходит до объяснения сбоя компиляции, а именно о выводе аргумента шаблона. –

2

Я думаю, что порядок событий

  • Компилятор не ищет функцию принимая char[10] собственно потому, что язык не поддерживает передачу массивов в качестве значений.
  • Компилятор ищет функцию, ссылающуюся на ссылку на char[10] (и не находит).
  • Компилятор ищет функцию с указателем на char, который является фактическим типом аргумента после так называемого типа настройки и не находит.

Последний пункт интересен тем, что функция шаблон f фактически действительно принимает указатель на символ, как пояснялось другие плакаты: индекс в декларации является излишним, и в объявлении функции f(char p[])p не типа массив, но указатель типа на char. Обратите внимание, что это отличается от деклараций такого рода в другом месте (а не как параметр функции), где p будет массивом, хотя и неполным.

Причина, по которой компилятор не может создать экземпляр шаблона функции, заключается не в том, что его аргумент неправильный: он будет соответствовать настройке типа аргумента. Причина в том, что не может вывести параметр шаблона N из аргумента. В конце концов, для каждого N был бы другой f: какой должен компилятор взять ?? После того, как фактический аргумент buf был «скорректирован» на указатель на его первый элемент, информация о длине в аргументе теряется. (Да, компиляторы глупы.)

Информация о длине сохранялась, когда вы объявили функцию ссылкой на массив.

Другая возможность состоит в том, чтобы просто создать экземпляр шаблона функции в явном виде:

f<10>(buf); работы.