解引用带有默认参数的函数 - C++14 vs C++11

20

以下代码无法使用选项-std=c++1y与g++ 5.4.0编译:

void f(int=0) ;

int main() {
    f(); // ok
    (*f)(2);// ok
    (*f)();// ok c++11; error with c++14: too few arguments to function
    return 0;
}

函数声明了默认参数,那么这里有什么问题呢?感谢您的帮助。

为什么 g++ -c -std=c++11 编译通过了呢?


1
显而易见的答案是尝试使用更新的 g++ 版本。5行已经过时,而5.4甚至不是它最新的小版本。在这种情况下,搜索GCC Bugzilla也是明智的选择,因为问题可能已经被发现,但是在较旧的版本中进行过滤可能需要一段时间,有时甚至不会发生。 - underscore_d
似乎是编译器的一个错误。Clang无论是在C++11还是C++14模式下都会拒绝这段代码。 - StoryTeller - Unslander Monica
这是否与优化步骤的顺序有关?即在处理参数之前,函数指针被优化为直接调用。 - underscore_d
2个回答

25

(*f)()作为有效的语法是GCC的一个bug。标准规定,使用一元运算符*与函数名一起应该会导致函数名退化为指针,然后对指针进行解引用以获取调用表达式的函数地址。

但是GCC似乎比较聪明,省略了上述行为。它将(*f)简单地视为f。而且可以使用默认参数来调用f

然而,可以通过强制使用一元运算符+来强制进行退化。因此以下两个表达式:

(+f)();
(*+f)();

在标准修订版中,通过这个命令引起GCC发出error: too few arguments to function错误,在GCC 7.2GCC 6.3中都可以。


上面@StoryTeller提到Clang拒绝了C++11和C++14中的OP代码。 Clang是否有相同的错误? - KeithSmith
6
我是故事讲述人@KeithSmith。Clang拒绝了原始代码,这正是它应该做的。它在这里没有出现错误。 - StoryTeller - Unslander Monica
Visual Studio 2017 愉快地接受原始代码。 (+f)() 和 (*+f)(),以及 (+*f)() -- 都导致内部编译器错误。 - Alex Guteniev
@AlexanderGutenev - 一致性很重要 :) 我很惊讶 MSVC 竟然搞砸了这个。一元 + 的规范非常简单... - StoryTeller - Unslander Monica

8

默认参数不属于函数类型,因此当您隐式地将函数转换为函数指针并间接引用该指针时,这些参数将被丢弃。


3
为什么 g++ -c -std=c++11 可以编译? - Pavlo Rudenko
我不确定,我认为它也不应该编译。 - Alex Guteniev
@StoryTeller 是的,它在右侧边栏中间垂直附近:语言:C++14(gcc 6.3) - underscore_d
2
@underscore_d - 那我改口道歉。那个链接证明了GCC的错误变得更糟了。 - StoryTeller - Unslander Monica
2
我的coliru with GCC 7.2测试表明该bug仍然存在。 - StoryTeller - Unslander Monica
显示剩余2条评论

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