Функция и указатель на неё

274
14 декабря 2021, 06:30

Насколько я знаю для функций в с++ (в силу исторических причин) верно следующее тождество:

foo == &foo;

Тобишь указатель на функцию это тоже что и функция и наоборот. Однако, типы у этих значений разные:

std::is_same<decltype(foo), decltype(&foo)>::value == false;

Почему типы разные? И какие они?

Answer 1

Типы у функции и указателя на функцию действительно совершенно разные. Однако поведение значений типа "функция" в выражениях в С и С++ во многом аналогично поведению значений типа "массив": во многих контекстах в выражениях значение типа "функция" само по себе, безо всякого участия с вашей стороны неявно преобразуется ("decays") к значению типа "указатель на функцию".

Ваш пример с оператором == - как раз пример такого контекста. Формально слева у вас стоит функция, а справа - указатель на функцию, который вы получили при помощи оператора &. Но фактически до оператора == левый операнд "доходит" уже преобразованным к типу "указатель на функцию". Этот указатель "получился сам", как результат вышеупомянутого неявного преобразования.

Соверешенно аналогичным образом для массива int a[10] выполняется равенство

&a[0] == a

несмотря на то, что исходные типы в левой и правой части этого равенства совершенно разные.

Для случая функции будут выполняться также и равенства

*foo == &foo
***foo == ***&***&**foo;

и т.п.

В таких контекстах, как унарный оператор &, оператор sizeof, спецификатор decltype и др., неявного преобразования не происходит. Поэтому в этих контекстах вы видите истинный, непреобразованный тип функции. (То же самое справедливо и для массивов).

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

Например, объявление

decltype(foo) a = foo;

является некорректным. decltype(foo) видит тип "функция", в результате чего идентификатор a объявляется с типом "функция". Функцию невозможно "инициализировать".

В то же время, согласно правилам поведения decltype, вот такое объявление

decltype((foo)) b = foo;

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

READ ALSO
Передача в __global__ функцию массива

Передача в __global__ функцию массива

К примеру есть такой код:

190
Как отсортировать двумерный vector

Как отсортировать двумерный vector

Есть условный, уже инициализированный 2х вектор:

100
Проблема с таймером с++

Проблема с таймером с++

Помогите разобраться, стоит задача: нужно по таймеру вызывать функцию в другом потоке Вот что у меня получается

178