Почему для определения функции нельзя использовать 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.
Список аргументов должен быть явно указан в деклараторе; он не может быть унаследован от 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
во время компиляции.