不寻常的C++函数声明

10

有几种合法的方式可以在C++中声明函数。

其中一些合法方法包括:

void function ();
void function (void);
dataType function (dataType);

and so on...

最近,我遇到了这样的一个函数声明:

void (function) ();  //Take note of the braces around the function name

我以前从未见过这样的东西,在测试它时,我在C++编译器中运行它,没有任何警告或编译错误。

我的问题是: 为什么void (function) ();是声明函数原型的一种合法方式?声明函数采用这种方式有特殊的含义吗?还是像其他函数声明一样正常工作?


2
为什么(5)是合法的整数表达式?同样的问题也存在于(void function (void)),你会问为什么不行呢?这是一个漫长而悲伤的故事,它起源于一个有趣但完全误导的概念:“声明语法遵循使用语法”,我们被困在其中。 - n. m.
1
我想指出void function (void);实际上是C语法。 - Stefan Falk
6个回答

12

一个区别是用括号将其包裹起来可以防止预处理器对函数式宏进行扩展。正如其他答案中提到的那样,这对于实际编译器并没有任何区别。

例如:

// somewhere buried deep in a header
#define function(a, b) a + b

// your code
void function() {  // this expands the macro and gives compilation error
}

void (function)() { // this does not expand and works as expected
}

这在IT技术中非常有用,比如微软Visual Studio库背后的聪明头脑决定提供类似函数的宏,例如minmax。 (还有其他方法,如#undef可绕过此问题)。
请注意,对象宏(例如#define function 3 + 4)仍将被扩展。
预处理器只是一个愚钝的文本替换工具(相对于编译器而言,编译器是一个(聪明的)文本替换工具)。 它获取宏定义并在所有位置进行替换。 它不知道所替换内容的语义。
例如:
// somewhere buried deep in a header
#define function 3 + 2

// your code
void function() {
}

预处理器看到单词function,并在文本中将其替换为字符串3 + 2。他不知道function是函数声明和定义的id名称部分。预处理阶段后,实际编译阶段开始。因此,编译器实际上看到:

// your code
void 3 + 2() {
}

对他来说毫无意义且出现错误。

对于类似函数的宏定义

// somewhere buried deep in a header
#define function(a, b) a + b

预处理器也是做同样的事情,只不过它期望由逗号分隔的两个括号中的“标记”(即参数),并进行替换。 (再次不考虑语义):

int d = function(2, 3);
//will be replaced by the preprocessor to:
int d = 2 + 3; // passes compilation phase

void function();
// the preprocessor doesn’t find the arguments for function so it gives an error.

然而,如果遇到 (function) ,它不会尝试扩展它(忽略它)。这只是一个规则。


你介意再解释一下宏展开的原理,以及为什么在函数名周围加上大括号会有所不同吗?:) 谢谢! - user3437460

3

这与...相同。

void function();

您可以将其声明为:

您可以将其声明为

void ((function)) ();

如果你想:)

注意不要将这个与函数指针声明语法混淆。


所以我想这就像 int x = (3);,括号是多余的,可以省略掉?谢谢你的回复。 - user3437460
基本上是这样。虽然像bolov所说,宏有一个我在回答时忽略的小差别 :) - Shikamu

0

我认为你可能会发现那是:

void (*function) ();

既然使用void (function)();或者void (((((function)))))();没有任何好处,它们是等价的。如果我错了,而这不是一个打字错误,那么答案就是你可以在函数名周围放置任意数量的括号,但要遵守编译器的限制,就像下面的output6()代码一样。

如果我没有弄错,那个带有*的实际上声明了一个函数指针,它可以用来保存指向函数的指针。它根本没有声明一个函数,只是一个可以用来引用函数的指针。

就像一个int指针(例如),函数指针可以指向任意函数,参数无关紧要。

例如:

#include <iostream>

void (((((output6)))))() { std::cout << 6; }
void output7() { std::cout << 7; }
void output8() { std::cout << 8; }
void (*fn)();

int main() {
    fn = &output6; fn();
    fn = &output7; fn();
    fn = &output8; fn();
    std::cout << '\n';
}

将输出678


那么我可以说在我的情况下 void function()void (function)() 是一样的吗? - user3437460
为什么要踩这个回答?这个回答里没有任何错误,我非常确定 OP 只是打错了,因为没有任何熟练的程序员会使用 void (function)(); - paxdiablo
我认为你被踩是因为你假设他打错了字(尽管我认为在OP的情况下只是(function)())- 话虽如此,你的回答写得很好,信息量大且详细,提供了所有关键信息。我会给你点赞。 - Mike

0

这并没有什么特别的,它与没有括号的版本完全相同。这只是语法声明方式的产物。通常在声明函数指针时,你会看到在函数名周围使用括号,例如:

void (*function_pointer)() = nullptr;
// a function pointer to a function taking and returning void

与...相比

void *function();
// a function declaration of a function taking void and returning void*

0

它对应于C++语法。如果简化,则定义声明符的规则之一如下:

declarator:

   (declarator)

所以你可以举个例子写成

void (function) (); 

或者

void ( (function) () );

或者甚至以下方式

struct A
{
   void ( ( function )() const );
};   

0

我认为它的工作方式与普通函数相同,因为函数指针的声明方式是:void (*function)(),所以如果省略了*,那么它应该只是一个函数。


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