вызов функции С++ с квадратной скобкой

int func(int n)
{return n;}

int main()
{ cout << func[4] ;
cout << func[4,3,5] ;}

что они на самом деле означают? Я думаю, что речь идет о доступе к func + 4, а func выделяется пространство при вызове func [4]. Но, func [4,3,5] просто абсурд.

Ответ 1

Причина, по которой этот код компилируется, и func[4] не является синтаксической ошибкой:

1. Типы функций могут неявно преобразовывать в указатели того же типа. Итак, если у нас есть такой код:

int f(int);

using func_t = int(*)(int);

void g(func_t);

мы можем написать

g(f)

и не вынуждены писать g(&f). &, Взяв нас от типа int(int) до int(*)(int) происходит неявно.

2.In C (и обязательно в C++ для совместимости) указатели подключены к массивам, а когда p - указатель p[x], то он совпадает с *(p + x). Итак, func[4] совпадает с *(func + 4).

3. *(p+x) имеет тип функции int(int), но снова может неявно распадаться на тип указателя, когда это необходимо. Итак *(func + 4) может быть неявным просто (func + 4).

4. Проигрыватели любого типа могут быть загружены в std::cout.


Обратите внимание, что только потому, что это не синтаксическая ошибка, это не значит, что она действительна. Конечно, это неопределенное поведение, и, поскольку предупреждение компилятора, испускаемое gcc и clang, указывает, что арифметика указателя с указателем функции обычно неправильна, потому что вы не можете создать массив функций. Реализация ставит функции, тем не менее, нравится. (Вы можете создать массив указателей на функции, но это совсем другое.)


Редактировать: я должен исправить себя - этот ответ не совсем корректен. func[4] неверна, поскольку указатель не является указателем на тип объекта. Ответ @holyblackcat правильный, см. его ответ для справки в стандарте.

Этот код должен быть плохо сформирован, и gcc только компилирует его без ошибки, потому что по умолчанию используется нестандартное расширение. Clang и msvc корректно отклоняют этот код.

Ответ 2

Я удивлен, что ни один ответ не упоминает об этом, но:

Код в вопросе просто недействителен C++.

Он отклонен Кланом и MSVC без флагов. GCC отвергает его с помощью -pedantic-errors.

a[b] (при отсутствии перегрузки оператора) определяется как *(a + b), а встроенный оператор + требует, чтобы операнд указателя являлся указателем на тип объекта (который не имеет указателей функций).

[expr.add]/1

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

(Акцент мой.)


GCC компилирует код, потому что расширение, позволяющее арифметику по указателю функции, включено по умолчанию.

Из-за распада func[4] -указателя func[4] рассматривается как &(&func)[4], что эффективно означает &func + 4, который (как поясняет ссылка) просто добавляет 4 к численному значению указателя. Вызов результирующего указателя, скорее всего, приведет к сбою или непредсказуемости результатов.

std::cout не имеет перегрузки << подходящий для печати указателей функций, и наилучшая подходящая перегрузка, которую может найти компилятор, является той, которая предназначена для печати bool s. Указатель преобразуется в bool, и поскольку он не равен null, он становится true, который затем печатается как 1.

И, наконец, func[4,3,5] имеет тот же эффект, что и func[5], так как в этом контексте , рассматривается как оператор, а x, y равен y.

Ответ 3

Так как он еще не упоминался: func[3, 4, 5] идентичен func[5] - в запятых есть встроенный запятый оператор, который оценивает левое выражение, отбрасывает его, а затем оценивает правую сторону выражение. Здесь нет вызова функции, и запятые в коде не ограничивают параметры функции.

Ответ 4

Да, речь идет о доступе к func + 4, который еще не определен, что приводит к значению мусора. Таким образом, компилятор укажет вам следующее предупреждающее сообщение.

hereProgram: In function 'int main()':
Program:7: warning: pointer to a function used in arithmetic