Из п. 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.
Хотя этот вопрос о C ++, но так как C ++ наследует typedef
и указатель на функцию из C, поэтому здесь можно использовать объяснение того же вопроса в C. Есть формальное объяснение C.
Обоснование международного стандарта — Языки программирования C §6.9.1 Определения функций
Список аргументов должен явно присутствовать в деклараторе; это не может быть унаследовано от
typedef
(см. §6.7.5.3). То есть, учитывая определение:typedef int p(int q, int r);
следующий фрагмент недействителен:
p funk // weird { return q + r ; }
Некоторые текущие реализации переписывают тип, например,
char
параметр, как если бы он был объявленint
поскольку известно, что аргумент передается какint
в отсутствие прототипа. Стандарт требует, однако, чтобы полученный аргумент был преобразован, как если бы он был назначен при входе в функцию. Переписывание типов, таким образом, больше не допустимо.
Это, вероятно, в основном исторические причины. typedef
был относительно поздним дополнением к C и был добавлен в существующий язык (и вызвал некоторые проблемы на этапе синтаксического анализа компиляторов).
Кроме того, функция определение должен определить имена параметров, если таковые имеются. Функция тип включает в себя тип возвращаемого значения функции и типы параметров, но не имена ее параметров. Например, эти:
void (int)
void (int x)
void (int y)
три способа написания одного и того же типа функции. Если у тебя есть:
typedef void func_t(int);
тогда это гипотетическое определение:
func_t some_func { }
не будет определять имя для его int
параметр. Я не уверен, как это могло быть решено разумным способом. Это было бы возможно, я полагаю, но это никогда не было сделано.
Но суть, вероятно, просто в том, что Деннис Ритчи тоже не думал, что стоит попытаться определить, как typedef
может быть использован в определении функции, или он просто не думал об этом.
Позвольте мне сказать несколько слов. Рассмотрим утверждение:
typedef void F(int p1, char* p2);
Это утверждение присваивает имя F
подписи функции void (int, char*);
Это определение псевдонима подписи функции. После этого заявление:
F fv;
говорит, что есть функция fv
, У него есть подпись, о которой говорилось выше, и где-то есть его тело. Посмотрите на синтаксис C / C ++ определения функции:
retType funcName(params) { body }
На самом деле используются 2 имени retType
а также funcName
, Ни один из них не совпадает с именем F
из начального определения типа. Имя F
имеет значение обоих имен. Если бы язык позволял что-то вроде:
F { body }
это свяжет тело с типом функции. Но это приводит к проблеме:
Значение F
было бы не понятно. Это «псевдоним сигнатуры функции» или «имя точки входа в код»?
Плюс синтаксис последнего примера был бы странным для миллионов программистов на C / C ++.
Правило так, как вы цитировали — typedef of function type shall not be used to define a function
, В 3-й строке примера вы пытаетесь определить функцию с типом функции F
, Это не разрешено стандартом.
РЕДАКТИРОВАТЬ
Как вы указали, я пытаюсь объяснить больше об этом.
Для 3-й строки, если это допустимо, вы можете заменить F на определение typedef:
void fv { }()
, Это не юридическое определение или объявление в C ++.
Я думаю, что ключевым моментом является то, что typedef
просто создает псевдоним для упрощения, и вы можете заменить свой тип typedef, как замена #define
во время компиляции.