Почему для определения функции нельзя использовать typedef функции?

Из п. 8.3.5.11 ИСО/МЭК 14882: 2011 (E):

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

Далее приводится следующий стандарт:

typedef void F();
F fv; // OK: equivalent to void fv();
F fv { } // ill-formed
void fv() { } // OK: definition of fv

Что мотивирует это правило? Кажется, он ограничивает потенциальную выразительную полезность функций typedefs.

Ответ 1

Хотя этот вопрос касается С++, но поскольку С++ наследует typedef и указатель на функцию из C, поэтому здесь можно использовать объяснение того же вопроса в C. Там формальное объяснение для C.

Обоснование для международного стандарта - Языки программирования C §6.9.1 Определения функций

Список аргументов должен быть явно указан в деклараторе; он не может быть унаследован от a typedef (см. §6.7.5.3). То есть, учитывая определение:

typedef int p(int q, int r);

недействителен следующий фрагмент:

p funk // weird
{ return q + r ; }

Некоторые текущие реализации переписывают тип, например, параметр char, как если бы он был объявлен int, поскольку, как известно, аргумент передается как int в отсутствие прототипа. Стандарт требует, однако, чтобы полученный аргумент был преобразован, как если бы он был присвоен при вводе функции. Таким образом, переписывание типов больше не допустимо.

Ответ 2

Вероятно, это главным образом исторические причины. typedef был относительно поздним дополнением к C и был привязан к существующему языку (и вызвал несколько проблем для фазы синтаксического анализа компиляторов).

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

void (int)
void (int x)
void (int y)

- три способа записи одного и того же типа функции. Если у вас есть:

typedef void func_t(int);

то это гипотетическое определение:

func_t some_func { }

не будет определять имя для параметра int. Я не знаю, как это могло быть разрешено разумным образом. Возможно, возможно, но это никогда не было сделано.

Но нижняя строка, вероятно, заключается только в том, что Деннис Ритчи или не думал, что стоит попытаться определить, как typedef можно использовать в определении функции, или он просто не думал об этом.

Ответ 3

Позвольте мне сказать несколько слов. Рассмотрим утверждение:

typedef void F(int p1, char* p2);

Этот оператор присваивает имя F сигнатуре функции void (int, char*); Это определение псевдонима для сигнатуры функции. После этого утверждение:

F fv;

указывает, что существует функция fv. У него есть подпись, о которой говорилось выше, и где-то ее тело. Посмотрите на синтаксис C/С++ определения функции:

retType  funcName(params) { body }

На самом деле есть 2 имени retType и funcName. Ни один из них не совпадает с именем F из первоначального typedef. Имя F имеет смысл обоих имен. Если язык допустил бы что-то вроде:

F { body }

это свяжет тело с типом функции. Но это приводит к проблеме:

Значение F будет неясным. Является ли это "псевдоним сигнатуры функции" или это "имя точки входа в код"?

Плюс синтаксис последнего примера будет странным для миллионов программистов на C/С++.

Ответ 4

Это правило, как вы указали, - typedef of function type shall not be used to define a function. В третьей строке примера вы пытаетесь определить функцию с типом функции F. Это запрещено стандартом.


ИЗМЕНИТЬ
Как вы указали, я пытаюсь объяснить об этом больше.

Для третьей строки, если она была законной, вы можете заменить F на определение typedef:
void fv { }(). Это не является юридическим определением или декларацией в С++.

Я думаю, что ключевым моментом является то, что typedef просто создает псевдоним для упрощения, и вы можете заменить тип typedef, например замену #define во время компиляции.