为什么不能使用函数的typedef来定义一个函数?

12

来自ISO/IEC 14882:2011(E)第8.3.5.11节:

函数类型的typedef可以用于声明函数,但不得用于定义函数。

标准继续给出了以下示例:

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

这个规则的动机是什么?它似乎限制了函数类型定义的表达上的潜在用途。


1
想一想:typedef 为另一个类型创建了一个别名,这在你的情况下是一个函数类型。对于第三个(不良形式)的示例,F 是指函数的返回类型还是函数本身的类型? - Mark Garcia
2
@MarkGarcia:它将是函数本身的类型,因为没有括号限定参数。换句话说,如果语言允许,它可以被明确地解决;只是它不允许。 - Keith Thompson
2
@KeithThompson 那个语句给了我一些想法。好,那函数的参数呢?如果你用那种方式定义函数,你会怎么引用函数参数? - Mark Garcia
@MarkGarcia:是的,看我的回答。 - Keith Thompson
4个回答

13

虽然这个问题是关于C++的,但由于C++从C中继承了typedef和函数指针,因此可以使用C中相同问题的解释。在C中有一个正式的解释。

国际标准的理由 - 编程语言C §6.9.1 函数定义

参数列表必须在声明符中显式地存在;它不能从typedef中继承(参见§6.7.5.3)。也就是说,给定以下定义:

typedef int p(int q, int r);
以下片段无效:

the following fragment is invalid:


以下代码片段无效:

以下代码片段无效:

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

目前有些实现会将一个char类型的参数重写为int类型,因为在没有原型的情况下,已知该参数作为int类型传递。然而,标准要求函数在进入时将接收到的参数像赋值一样进行转换。因此,不再允许进行类型重写。


2
我想看一份类似的 C++ 标准的理论文档,有吗?(到目前为止,我读过的最好的是 Stroustrup 的书...) - gx_
@ gx_ 据我所知没有。我也很想看到一个。 - Yu Hao

8

这可能主要是历史原因。 typedef 是相对较晚加入 C 语言的,并且被附加到现有的语言上(并为编译器的解析阶段带来了一些问题)。

此外,函数定义必须定义参数的名称(如果有)。函数类型包括函数的返回类型和参数类型,但不包括其参数名称。例如:

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

有三种方式编写同一函数类型。如果您有以下代码:
typedef void func_t(int);

那么这个假设的定义是:
func_t some_func { }

该函数没有为其int参数定义名称。我不确定如何以合理的方式解决这个问题。我想这是可能的,但从未实现过。

但最重要的是,Dennis Ritchie可能认为定义如何在函数定义中使用typedef不值得花费精力,或者他根本没有想到。


但是拥有无名参数并且无法引用它们是完全可以的。因此,您的假设与编写 void some_func(int) { } 相同。 - Benjamin Lindley
2
@BenjaminLindley:是的,但这意味着通过typedef定义的任何函数都不能有命名参数。这将是一个令人烦恼和武断的限制。没有能力将其推广,允许一个特殊情况是不值得的。在C语言中,typedef起源的地方,函数定义中不允许无名称的参数。 - Keith Thompson
1
不知道 C 语言有这个特性。 - Benjamin Lindley

1
让我说几句。考虑以下陈述:

Let me put a few words. Consider a statement:

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

这个语句将名称F赋值给函数签名void (int, char*)。这是一个函数签名的别名定义。随后的语句:
F fv;

这段文字表明存在一个名为fv的函数。它具有上述提到的签名并且其函数体位于某处。请查看该函数定义的C/C++语法:

retType  funcName(params) { body }

实际上有两个名字被使用,分别是 retTypefuncName。它们都和最初的 typedef 中的名字 F 不同。名字 F 包含了这两个名字的意义。如果语言允许像下面这样的东西:
F { body }

这将把函数类型与主体关联起来。但这会导致一个问题:F的含义不清楚。它是“函数签名的别名”还是“代码入口点的名称”?此外,最后一个示例的语法对数百万C/C++程序员来说可能很奇怪。

-4
规则如你所引用的 - typedef 函数类型不应该用于定义函数。在示例的第三行,你试图使用函数类型F来定义一个函数。这是标准不允许的。

编辑
正如你所指出的,我会更详细地解释一下。

对于第三行,如果它是合法的,那么您可以使用typedef定义来替换F:
void fv { }()。 这不是C ++中的合法定义或声明。

我认为关键点在于,typedef只是为了简化而创建一个别名,并且您可以在编译期间像#define替换一样替换typedef类型。


但是这个规则的动机是什么? - Martin Drozdik
我认为他知道规则就是引用的那个。他是引用它的人,并且给出了具体章节和节。 - Benjamin Lindley
@BenjaminLindley 我重新编辑了我的帖子。你可以看一下并提出任何建议。 - Zachary
你仍然只是在重申它无效的事实。如果有效,那么F fv { }就是有效的。 - Keith Thompson
@KeithThompson 不合法。如果是的话,编译器会将 v {} 视为一个整体。将其集成到 typedef 中,它将变成 **void fv {}()**。这怎么合法呢? - Zachary
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接